From e9e2a24377325cd9263627c1830576916917c447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=90=E1=85=A2=E1=84=92=E1=85=AE?= =?UTF-8?q?=E1=86=AB?= Date: Thu, 11 Jul 2024 15:05:30 +0900 Subject: [PATCH 001/178] =?UTF-8?q?chore:=20webpack,=20react,=20typescript?= =?UTF-8?q?=20=ED=99=98=EA=B2=BD=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe , soi-ha , jinhokim98 --- client/.gitignore | 10 + client/.gitkeep | 0 client/index.html | 11 + client/package-lock.json | 5143 ++++++++++++++++++++++++++++++++++++++ client/package.json | 28 + client/src/App.tsx | 9 + client/src/index.tsx | 9 + client/tsconfig.json | 44 + client/webpack.config.js | 38 + 9 files changed, 5292 insertions(+) create mode 100644 client/.gitignore delete mode 100644 client/.gitkeep create mode 100644 client/index.html create mode 100644 client/package-lock.json create mode 100644 client/package.json create mode 100644 client/src/App.tsx create mode 100644 client/src/index.tsx create mode 100644 client/tsconfig.json create mode 100644 client/webpack.config.js diff --git a/client/.gitignore b/client/.gitignore new file mode 100644 index 000000000..b20b2e92f --- /dev/null +++ b/client/.gitignore @@ -0,0 +1,10 @@ +logs +*.log +npm-debug.log* + +node_modules +dist + +.env + +*storybook.log diff --git a/client/.gitkeep b/client/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/client/index.html b/client/index.html new file mode 100644 index 000000000..77aaf80a0 --- /dev/null +++ b/client/index.html @@ -0,0 +1,11 @@ + + + + + + 행동대장 + + +
+ + diff --git a/client/package-lock.json b/client/package-lock.json new file mode 100644 index 000000000..249f0c13e --- /dev/null +++ b/client/package-lock.json @@ -0,0 +1,5143 @@ +{ + "name": "haengdong-client", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "haengdong-client", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "fork-ts-checker-webpack-plugin": "^9.0.2", + "html-loader": "^5.0.0", + "html-webpack-plugin": "^5.6.0", + "ts-loader": "^9.5.1", + "typescript": "^5.5.3", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^5.0.4" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", + "dev": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.0.4.tgz", + "integrity": "sha512-aOcSN4MeAtFROysrbqG137b7gaDDSmVrl5mpo6sT/w+kcXpWnzhMjmY/Fh/sDx26NBxyIE7MB1seqLeCAzy9Sg==", + "dev": true, + "dependencies": { + "@jsonjoy.com/base64": "^1.1.1", + "@jsonjoy.com/util": "^1.1.2", + "hyperdyperid": "^1.2.0", + "thingies": "^1.20.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.2.0.tgz", + "integrity": "sha512-4B8B+3vFsY4eo33DMKyJPlQ3sBMpPFUZK2dr3O3rXrOGKKbYG44J0XSFkDo1VOQiri5HFEhIeVvItjR2xcazmg==", + "dev": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.56.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", + "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", + "dev": true, + "peer": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "peer": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true, + "peer": true + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.5", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", + "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "dev": true + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "node_modules/@types/http-proxy": { + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.14.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", + "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/react": { + "version": "18.3.3", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", + "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", + "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/retry": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "peer": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "peer": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true, + "peer": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true, + "peer": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "dev": true, + "peer": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dev": true, + "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.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bonjour-service": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", + "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "caniuse-lite": "^1.0.30001640", + "electron-to-chromium": "^1.4.820", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001641", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001641.tgz", + "integrity": "sha512-Phv5thgl67bHYo1TtMY/MurjkHhV4EDaCosezRXgZ8jzA/Ub+wjxAvbGvjoFENStinwi5kCyOYV3mi5tOGykwA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dev": true, + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "dev": true, + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.824", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.824.tgz", + "integrity": "sha512-GTQnZOP1v0wCuoWzKOxL8rurg9T13QRYISkoICGaZzskBf9laC3V8g9BHTpJv+j9vBRcKOulbGXwMzuzNdVrAA==", + "dev": true, + "peer": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", + "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/envinfo": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", + "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "dev": true, + "peer": true + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "peer": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "peer": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.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" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "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" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", + "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-9.0.2.tgz", + "integrity": "sha512-Uochze2R8peoN1XqlSi/rGUkDQpRogtLFocP9+PGu68zk1BDAKXfdeCdyVZpgTk8V8WFVQXdEz426VKjXLO1Gg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cosmiconfig": "^8.2.0", + "deepmerge": "^4.2.2", + "fs-extra": "^10.0.0", + "memfs": "^3.4.1", + "minimatch": "^3.0.4", + "node-abort-controller": "^3.0.1", + "schema-utils": "^3.1.1", + "semver": "^7.3.5", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">=12.13.0", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "typescript": ">3.6.0", + "webpack": "^5.11.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true, + "peer": true + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-5.0.0.tgz", + "integrity": "sha512-puaGKdjdVVIFRtgIC2n5dt5bt0N5j6heXlAQZ4Do1MLjHmOT1gCE1Ogg7XZNeJlnOVHHsrZKGs5dfh+XwZ3XPw==", + "dev": true, + "dependencies": { + "html-minifier-terser": "^7.2.0", + "parse5": "^7.1.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/html-loader/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/html-loader/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/html-loader/node_modules/html-minifier-terser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", + "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "~5.3.2", + "commander": "^10.0.0", + "entities": "^4.4.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.15.1" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + } + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", + "integrity": "sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==", + "dev": true, + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "dev": true, + "engines": { + "node": ">=10.18" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", + "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", + "dev": true, + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-network-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", + "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dev": true, + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "peer": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/launch-editor": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.0.tgz", + "integrity": "sha512-vJranOAJrI/llyWGRQqiDM+adrw+k83fvmmx3+nV47g3+36xM15jE+zyZ6Ffel02+xSvuM0b2GDRosXZkbb6wA==", + "dev": true, + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.9.3.tgz", + "integrity": "sha512-bsYSSnirtYTWi1+OPMFb0M048evMKyUYe0EbtuGQgq6BVQM1g1W8/KIUJCCvjgI/El0j6Q4WsmMiBwLUBSw8LA==", + "dev": true, + "dependencies": { + "@jsonjoy.com/json-pack": "^1.0.3", + "@jsonjoy.com/util": "^1.1.2", + "tree-dump": "^1.0.1", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">= 4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "peer": true + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "dev": true + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true, + "peer": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", + "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", + "dev": true, + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz", + "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "dev": true + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "peer": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dev": true, + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/rimraf": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", + "integrity": "sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": "14 >=14.20 || 16 >=16.20 || >=18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-applescript": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", + "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "peer": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/spdy-transport/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/spdy-transport/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/spdy/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/spdy/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.31.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.2.tgz", + "integrity": "sha512-LGyRZVFm/QElZHy/CPr/O4eNZOZIzsrQ92y4v9UJe/pFJjypje2yI3C2FmPtvUEnhadlSbmG2nXtdcjHOjCfxw==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/thingies": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", + "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", + "dev": true, + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "tslib": "^2" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tree-dump": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", + "integrity": "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==", + "dev": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/ts-loader": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", + "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-loader/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/watchpack": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", + "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", + "dev": true, + "peer": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/webpack": { + "version": "5.92.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.92.1.tgz", + "integrity": "sha512-JECQ7IwJb+7fgUFBlrJzbyu3GEuNBcdqr1LD7IbSzwkSmIevTm8PF+wej3Oxuz/JFBUZ6O1o43zsPkwm1C4TmA==", + "dev": true, + "peer": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.7.1", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.2.1.tgz", + "integrity": "sha512-hRLz+jPQXo999Nx9fXVdKlg/aehsw1ajA9skAneGmT03xwmyuhvF93p6HUKKbWhXdcERtGTzUCtIQr+2IQegrA==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^4.6.0", + "mime-types": "^2.1.31", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.0.4.tgz", + "integrity": "sha512-dljXhUgx3HqKP2d8J/fUMvhxGhzjeNVarDLcbO/EWMSgRizDkxHQDZQaLFL5VJY9tRBj2Gz+rvCEYYvhbqPHNA==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.13", + "@types/connect-history-api-fallback": "^1.5.4", + "@types/express": "^4.17.21", + "@types/serve-index": "^1.9.4", + "@types/serve-static": "^1.15.5", + "@types/sockjs": "^0.3.36", + "@types/ws": "^8.5.10", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.2.1", + "chokidar": "^3.6.0", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.4.0", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.1.0", + "launch-editor": "^2.6.1", + "open": "^10.0.3", + "p-retry": "^6.2.0", + "rimraf": "^5.0.5", + "schema-utils": "^4.2.0", + "selfsigned": "^2.4.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^7.1.0", + "ws": "^8.16.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-server/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } +} diff --git a/client/package.json b/client/package.json new file mode 100644 index 000000000..3f0fd4175 --- /dev/null +++ b/client/package.json @@ -0,0 +1,28 @@ +{ + "name": "haengdong-client", + "version": "1.0.0", + "description": "", + "type": "module", + "scripts": { + "start": "webpack serve ", + "build": "webpack --mode production" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "fork-ts-checker-webpack-plugin": "^9.0.2", + "html-loader": "^5.0.0", + "html-webpack-plugin": "^5.6.0", + "ts-loader": "^9.5.1", + "typescript": "^5.5.3", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^5.0.4" + }, + "dependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1" + } +} diff --git a/client/src/App.tsx b/client/src/App.tsx new file mode 100644 index 000000000..243a74f3c --- /dev/null +++ b/client/src/App.tsx @@ -0,0 +1,9 @@ +const App: React.FC = () =>{ + return( +
+ Hello, React with Webpack +
+ ); +} + +export default App; diff --git a/client/src/index.tsx b/client/src/index.tsx new file mode 100644 index 000000000..c018515cd --- /dev/null +++ b/client/src/index.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App'; + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +); diff --git a/client/tsconfig.json b/client/tsconfig.json new file mode 100644 index 000000000..5dfba11d7 --- /dev/null +++ b/client/tsconfig.json @@ -0,0 +1,44 @@ +{ + "compilerOptions": { + "sourceMap": true, + "module": "ES2020", + "target": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "useDefineForClassFields": true, + "removeComments": true, + "skipLibCheck": true, + + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + + "types": ["jest"], + "esModuleInterop": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictBindCallApply": true, + "strictPropertyInitialization": true, + "noImplicitAny": true, + "noImplicitThis": true, + "alwaysStrict": true, + "noImplicitReturns": true, + "forceConsistentCasingInFileNames": true, + + "baseUrl": "./", + "paths": { + "components/*": [ + "src/components/*" + ], + }, + "outDir": "./dist" + }, + "include": ["src"], +} \ No newline at end of file diff --git a/client/webpack.config.js b/client/webpack.config.js new file mode 100644 index 000000000..9cc915a78 --- /dev/null +++ b/client/webpack.config.js @@ -0,0 +1,38 @@ +import path from "path"; +import HtmlWebpackPlugin from 'html-webpack-plugin'; +import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; +import { fileURLToPath } from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +export default { + mode: 'development', + entry: "./src/index.tsx", + resolve: { + extensions: [".js", ".jsx", ".ts", ".tsx"], + }, + output: { + path: path.join(__dirname, "dist"), + filename: "bundle.min.js", + }, + module: { + rules: [ + { + test: /\.tsx?$/, + loader: 'ts-loader', + exclude: /node_modules/, + } + ] + }, + plugins: [ + new HtmlWebpackPlugin({ + template: "./index.html" + }), + new ForkTsCheckerWebpackPlugin(), + ], + devServer: { + port: 3000, + hot: true, + } +} \ No newline at end of file From dff70d7bee4c2d5c8d9b9a005dd78a4d8ceb28ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=90=E1=85=A2=E1=84=92=E1=85=AE?= =?UTF-8?q?=E1=86=AB?= Date: Thu, 11 Jul 2024 16:47:41 +0900 Subject: [PATCH 002/178] =?UTF-8?q?chore:=20eslint,=20prettier=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: JinHo Kim Co-authored-by: Pakxe --- client/.eslintrc.json | 87 + client/.gitignore | 1 + client/.npmrc | 1 + client/.prettierrc | 13 + client/index.html | 2 +- client/package-lock.json | 4110 +++++++++++++++++++++++++++++++------- client/package.json | 26 +- client/src/App.tsx | 10 +- client/src/index.tsx | 6 +- client/tsconfig.json | 80 +- client/webpack.config.js | 24 +- 11 files changed, 3548 insertions(+), 812 deletions(-) create mode 100644 client/.eslintrc.json create mode 100644 client/.npmrc create mode 100644 client/.prettierrc diff --git a/client/.eslintrc.json b/client/.eslintrc.json new file mode 100644 index 000000000..035405363 --- /dev/null +++ b/client/.eslintrc.json @@ -0,0 +1,87 @@ +{ + "extends": [ + "airbnb", + "airbnb/hooks", + "eslint:recommended", + "plugin:react/recommended", + "plugin:@typescript-eslint/recommended", + "plugin:react-hooks/recommended", + // "plugin:storybook/recommended", + "plugin:import/typescript", + "plugin:import/recommended", + "plugin:import/errors", + "plugin:import/warnings", + "prettier", // Prettier 설정을 ESLint에 추가 + "plugin:prettier/recommended" // + ], + "parser": "@typescript-eslint/parser", + "plugins": ["react", "@typescript-eslint", "import", "prettier"], + "rules": { + "prettier/prettier": "error", + "react/react-in-jsx-scope": "off", + "react/prop-types": "off", + "react/jsx-uses-vars": "error", + "@typescript-eslint/no-use-before-define": ["error"], + "@typescript-eslint/explicit-module-boundary-types": "error", + "import/order": [ + "error", + { + "newlines-between": "always", + "groups": ["type", "builtin", "external", "internal", "parent", "sibling", "index", "unknown"], + "pathGroups": [ + { + "pattern": "react*", + "group": "external", + "position": "before" + }, + { + "pattern": "@hooks/*", + "group": "internal", + "position": "after" + }, + { + "pattern": "@apis/*", + "group": "internal", + "position": "after" + }, + { + "pattern": "@pages/*", + "group": "internal", + "position": "after" + }, + { + "pattern": "@components/*", + "group": "internal", + "position": "after" + }, + { + "pattern": "@assets/*", + "group": "internal", + "position": "after" + }, + { + "pattern": "@utils/*", + "group": "internal", + "position": "after" + }, + { + "pattern": "@constants/*", + "group": "internal", + "position": "after" + } + ] + } + ] + }, + "settings": { + "import/resolver": { + "node": { + "extensions": [".js", ".jsx", ".ts", ".tsx"] + }, + "typescript": { + "directory": "./src" + } + }, + "import/parsers": {"@typescript-eslint/parser": [".ts", ".tsx"]} + } +} diff --git a/client/.gitignore b/client/.gitignore index b20b2e92f..afd0485d1 100644 --- a/client/.gitignore +++ b/client/.gitignore @@ -8,3 +8,4 @@ dist .env *storybook.log +.DS_Store diff --git a/client/.npmrc b/client/.npmrc new file mode 100644 index 000000000..d1cdf2f06 --- /dev/null +++ b/client/.npmrc @@ -0,0 +1 @@ +engine-strict = true \ No newline at end of file diff --git a/client/.prettierrc b/client/.prettierrc new file mode 100644 index 000000000..fce76bb96 --- /dev/null +++ b/client/.prettierrc @@ -0,0 +1,13 @@ +{ + "singleQuote": true, + "trailingComma": "all", + "printWidth": 120, + "tabWidth": 2, + "semi": true, + "arrowParens": "avoid", + "endOfLine": "auto", + "jsxSingleQuote": false, + "bracketSpacing": false, + "proseWrap": "preserve", + "useTabs": true +} \ No newline at end of file diff --git a/client/index.html b/client/index.html index 77aaf80a0..05702360a 100644 --- a/client/index.html +++ b/client/index.html @@ -1,4 +1,4 @@ - + diff --git a/client/package-lock.json b/client/package-lock.json index 249f0c13e..bd52102a9 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -10,18 +10,36 @@ "license": "ISC", "dependencies": { "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "react-router-dom": "^6.24.1" }, "devDependencies": { + "@eslint/compat": "^1.1.0", + "@eslint/js": "^9.6.0", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^7.16.0", + "@typescript-eslint/parser": "^7.16.0", + "eslint": "^9.6.0", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-jsx-a11y": "^6.9.0", + "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-react": "^7.34.3", + "eslint-plugin-react-hooks": "^4.6.2", "fork-ts-checker-webpack-plugin": "^9.0.2", + "globals": "^15.8.0", "html-loader": "^5.0.0", "html-webpack-plugin": "^5.6.0", + "prettier": "3.3.2", "ts-loader": "^9.5.1", "typescript": "^5.5.3", + "typescript-eslint": "^7.16.0", "webpack-cli": "^5.1.4", "webpack-dev-server": "^5.0.4" + }, + "engines": { + "node": ">=20.15.1", + "npm": ">=10.7.0" } }, "node_modules/@babel/code-frame": { @@ -132,6 +150,222 @@ "node": ">=10.0.0" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/compat": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.1.0.tgz", + "integrity": "sha512-s9Wi/p25+KbzxKlDm3VshQdImhWk+cbdblhwGNnyCU5lpSwtWa4v7VQCxSki0FAUrGA3s8nCWgYzAH41mwQVKQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.0.tgz", + "integrity": "sha512-A68TBu6/1mHHuc5YJL0U0VVeGNiklLAL6rRmhTCP2B5XjWLMnrX+HkO+IAXyHvks5cyyY1jjK5ITPQ1HGS2EVA==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-array/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@eslint/js": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.6.0.tgz", + "integrity": "sha512-D9B0/3vNg44ZeWbYMpBoXqNP4j6eQD5vNwIlGAuFRRzK/WtT/jvDQW3Bi9kkf3PMDMlM7Yi+73VLUsn5bJcl8A==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -294,6 +528,41 @@ "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", "dev": true }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -304,6 +573,26 @@ "node": ">=14" } }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@remix-run/router": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.17.1.tgz", + "integrity": "sha512-mCOMec4BKd6BRGBZeSnGiIgwsbLGp3yhVqAD8H+PxiRNEHgDpZb8J1TnrSDlg97t0ySKMQJTHCWBCmBpSmkF6Q==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@types/body-parser": { "version": "1.19.5", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", @@ -342,35 +631,6 @@ "@types/node": "*" } }, - "node_modules/@types/eslint": { - "version": "8.56.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", - "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", - "dev": true, - "peer": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dev": true, - "peer": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true, - "peer": true - }, "node_modules/@types/express": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", @@ -422,6 +682,12 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", @@ -537,165 +803,258 @@ "@types/node": "*" } }, - "node_modules/@webassemblyjs/ast": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", - "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", - "dev": true, - "peer": true, - "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", - "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.16.0.tgz", + "integrity": "sha512-py1miT6iQpJcs1BiJjm54AMzeuMPBSPuKPlnT8HlfudbcS5rYeX5jajpLf3mrdRh9dA/Ec2FVUY0ifeVNDIhZw==", "dev": true, - "peer": true, "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", - "@xtuc/long": "4.2.2" + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/type-utils": "7.16.0", + "@typescript-eslint/utils": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", - "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.16.0.tgz", + "integrity": "sha512-j0fuUswUjDHfqV/UdW6mLtOQQseORqfdmoBNDFOqs9rvNVR2e+cmu6zJu/Ku4SDuqiJko6YnhwcL8x45r8Oqxg==", "dev": true, - "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.12.1" + "@typescript-eslint/typescript-estree": "7.16.0", + "@typescript-eslint/utils": "7.16.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.0.tgz", + "integrity": "sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==", "dev": true, - "peer": true, "dependencies": { - "@xtuc/ieee754": "^1.2.0" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/typescript-estree": "7.16.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" } }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, - "peer": true, "dependencies": { - "@xtuc/long": "4.2.2" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", - "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", - "dev": true, - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-opt": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1", - "@webassemblyjs/wast-printer": "1.12.1" - } + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", - "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "node_modules/@typescript-eslint/parser": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.16.0.tgz", + "integrity": "sha512-ar9E+k7CU8rWi2e5ErzQiC93KKEFAXA2Kky0scAlPcxYblLt8+XZuHUZwlyfXILyQa95P6lQg+eZgh/dDs3+Vw==", "dev": true, - "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/typescript-estree": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.16.0.tgz", + "integrity": "sha512-8gVv3kW6n01Q6TrI1cmTZ9YMFi3ucDT7i7aI5lEikk2ebk1AEjrwX8MDTdaX5D7fPXMBLvnsaa0IFTAu+jcfOw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.16.0.tgz", + "integrity": "sha512-fecuH15Y+TzlUutvUl9Cc2XJxqdLr7+93SQIbcZfd4XRGGKoxyljK27b+kxKamjRkU7FYC6RrbSCg0ALcZn/xw==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", - "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.16.0.tgz", + "integrity": "sha512-a5NTvk51ZndFuOLCh5OaJBELYc2O3Zqxfl3Js78VFE1zE46J2AaVuW+rEbVkQznjkmlzWsUI15BG5tQMixzZLw==", "dev": true, - "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1" + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", - "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, - "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", - "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.16.0.tgz", + "integrity": "sha512-rMo01uPy9C7XxG7AFsxa8zLnWXTF8N3PYclekWSrurvhwiw1eW88mrKiAYe6s53AUY57nTRz8dJsuuXdkAhzCg==", "dev": true, - "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@xtuc/long": "4.2.2" + "@typescript-eslint/types": "7.16.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, "node_modules/@webpack-cli/configtest": { @@ -742,20 +1101,6 @@ } } }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true, - "peer": true - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true, - "peer": true - }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -781,14 +1126,13 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-import-attributes": { - "version": "1.9.5", - "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", - "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, - "peer": true, "peerDependencies": { - "acorn": "^8" + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "node_modules/ajv": { @@ -910,12 +1254,231 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", "dev": true }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.toreversed": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", + "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.9.1.tgz", + "integrity": "sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", + "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", + "dev": true, + "dependencies": { + "deep-equal": "^2.0.5" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1010,39 +1573,6 @@ "node": ">=8" } }, - "node_modules/browserslist": { - "version": "4.23.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", - "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "peer": true, - "dependencies": { - "caniuse-lite": "^1.0.30001640", - "electron-to-chromium": "^1.4.820", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.1.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -1111,27 +1641,6 @@ "tslib": "^2.0.3" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001641", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001641.tgz", - "integrity": "sha512-Phv5thgl67bHYo1TtMY/MurjkHhV4EDaCosezRXgZ8jzA/Ub+wjxAvbGvjoFENStinwi5kCyOYV3mi5tOGykwA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "peer": true - }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1184,16 +1693,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/chrome-trace-event": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", - "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6.0" - } - }, "node_modules/clean-css": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", @@ -1417,15 +1916,116 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "dev": true }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, "dependencies": { "ms": "2.0.0" } }, + "node_modules/deep-equal": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.5", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.2", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-equal/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -1504,6 +2104,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -1529,6 +2146,18 @@ "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "dev": true }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/dns-packet": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", @@ -1541,6 +2170,18 @@ "node": ">=6" } }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/dom-converter": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", @@ -1627,13 +2268,6 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "dev": true }, - "node_modules/electron-to-chromium": { - "version": "1.4.824", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.824.tgz", - "integrity": "sha512-GTQnZOP1v0wCuoWzKOxL8rurg9T13QRYISkoICGaZzskBf9laC3V8g9BHTpJv+j9vBRcKOulbGXwMzuzNdVrAA==", - "dev": true, - "peer": true - }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -1692,6 +2326,66 @@ "is-arrayish": "^0.2.1" } }, + "node_modules/es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/es-define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", @@ -1713,21 +2407,107 @@ "node": ">= 0.4" } }, - "node_modules/es-module-lexer": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", - "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", "dev": true, - "peer": true + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "node_modules/es-get-iterator/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/es-iterator-helpers": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", + "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", "dev": true, - "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.1.2" + }, "engines": { - "node": ">=6" + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/escape-html": { @@ -1745,116 +2525,687 @@ "node": ">=0.8.0" } }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "peer": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "node_modules/eslint": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.6.0.tgz", + "integrity": "sha512-ElQkdLMEEqQNM9Njff+2Y4q2afHk7JpkPvrd7Xh7xefwgQynqPxwf55J7di9+MEibWUGdNjFF9ITG9Pck5M84w==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/config-array": "^0.17.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.6.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.0.1", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "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" + }, + "bin": { + "eslint": "bin/eslint.js" }, "engines": { - "node": ">=8.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", "dev": true, - "peer": true, "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" } }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "peer": true, - "engines": { - "node": ">=4.0" + "dependencies": { + "ms": "^2.1.1" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "node_modules/eslint-import-resolver-node/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-module-utils": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", "dev": true, - "peer": true, + "dependencies": { + "debug": "^3.2.7" + }, "engines": { - "node": ">=4.0" + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "engines": { - "node": ">= 0.6" + "dependencies": { + "ms": "^2.1.1" } }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "node_modules/eslint-module-utils/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "peer": true, + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, "engines": { - "node": ">=0.8.x" + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" } }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.2", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.6.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.9.0.tgz", + "integrity": "sha512-nOFOCaJG2pYqORjK19lqPqxMO/JpvdCZdPtNdxY3kvom3jTvkAbOvQvD8wuD0G8BYR0IGAGYDlzqWJOh/ybn2g==", + "dev": true, + "dependencies": { + "aria-query": "~5.1.3", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.9.1", + "axobject-query": "~3.1.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "es-iterator-helpers": "^1.0.19", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.0" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "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 + } + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.34.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.3.tgz", + "integrity": "sha512-aoW4MV891jkUulwDApQbPYTVZmeuSyFrudpbTAQuj5Fv8VL+o6df2xIGpw8B0hPjAaih1/Fb0om9grCdyFYemA==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.toreversed": "^1.1.2", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.19", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.8", + "object.fromentries": "^2.0.8", + "object.hasown": "^1.1.4", + "object.values": "^1.2.0", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.11" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", + "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-react/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.1.tgz", + "integrity": "sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "dev": true, + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.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", @@ -1888,12 +3239,40 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, "node_modules/fastest-levenshtein": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", @@ -1903,6 +3282,15 @@ "node": ">= 4.9.1" } }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/faye-websocket": { "version": "0.11.4", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", @@ -1915,6 +3303,18 @@ "node": ">=0.8.0" } }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -1967,6 +3367,25 @@ "flat": "cli.js" } }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, "node_modules/follow-redirects": { "version": "1.15.6", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", @@ -1987,6 +3406,15 @@ } } }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/foreground-child": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", @@ -2138,6 +3566,33 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-intrinsic": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", @@ -2169,6 +3624,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", @@ -2201,12 +3673,53 @@ "node": ">= 6" } }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "node_modules/globals": { + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.8.0.tgz", + "integrity": "sha512-VZAJ4cewHTExBWDHR6yptdIBlx9YSSZuwojj9Nt5mBRXQzrKakDsVKQ1J63sklLvzAJm0X5+RpO4i3Y2hcOnFw==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, - "peer": true + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/gopd": { "version": "1.0.1", @@ -2226,12 +3739,27 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, "node_modules/handle-thing": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", "dev": true }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2277,6 +3805,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -2505,189 +4048,537 @@ "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", "dev": true }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "dev": true, + "engines": { + "node": ">=10.18" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", + "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", "dev": true, "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "hasown": "^2.0.2" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/http-parser-js": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", - "dev": true - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", "dev": true, "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" + "is-typed-array": "^1.1.13" }, "engines": { - "node": ">=8.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "dev": true, "dependencies": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@types/express": "^4.17.13" + "node": ">= 0.4" }, - "peerDependenciesMeta": { - "@types/express": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", "dev": true, + "bin": { + "is-docker": "cli.js" + }, "engines": { - "node": ">=10.17.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/hyperdyperid": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", - "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "engines": { - "node": ">=10.18" + "node": ">=0.10.0" } }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", "dev": true, "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "call-bind": "^1.0.2" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", "dev": true, "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=6" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", "dev": true, "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" + "is-docker": "^3.0.0" }, "bin": { - "import-local-fixture": "fixtures/cli.js" + "is-inside-container": "cli.js" }, "engines": { - "node": ">=8" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/interpret": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", - "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, "engines": { - "node": ">=10.13.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ipaddr.js": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", - "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "node_modules/is-network-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", + "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", "dev": true, "engines": { - "node": ">= 10" + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, "dependencies": { - "binary-extensions": "^2.0.0" + "has-tostringtag": "^1.0.0" }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, "engines": { "node": ">=8" } }, - "node_modules/is-core-module": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", - "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "dependencies": { - "hasown": "^2.0.2" + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -2696,124 +4587,128 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "dev": true, - "bin": { - "is-docker": "cli.js" - }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", "dev": true, + "dependencies": { + "call-bind": "^1.0.7" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "dev": true, "dependencies": { - "is-extglob": "^2.1.1" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-inside-container": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dev": true, "dependencies": { - "is-docker": "^3.0.0" - }, - "bin": { - "is-inside-container": "cli.js" + "has-symbols": "^1.0.2" }, "engines": { - "node": ">=14.16" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-network-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", - "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", "dev": true, + "dependencies": { + "which-typed-array": "^1.1.14" + }, "engines": { - "node": ">=16" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "dev": true, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "dev": true, "dependencies": { - "isobject": "^3.0.1" + "call-bind": "^1.0.2" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "node_modules/is-weakset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-wsl": { @@ -2852,6 +4747,19 @@ "node": ">=0.10.0" } }, + "node_modules/iterator.prototype": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + } + }, "node_modules/jackspeak": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", @@ -2867,21 +4775,6 @@ "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "peer": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -2899,6 +4792,12 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -2911,6 +4810,24 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -2923,6 +4840,30 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -2932,6 +4873,24 @@ "node": ">=0.10.0" } }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "dev": true + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/launch-editor": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.0.tgz", @@ -2942,22 +4901,25 @@ "shell-quote": "^1.8.1" } }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, - "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6.11.5" - } - }, "node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -2976,6 +4938,12 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -3042,6 +5010,15 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -3127,6 +5104,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/minipass": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", @@ -3155,6 +5141,12 @@ "multicast-dns": "cli.js" } }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -3164,13 +5156,6 @@ "node": ">= 0.6" } }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true, - "peer": true - }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -3196,13 +5181,6 @@ "node": ">= 6.13.0" } }, - "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true, - "peer": true - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -3218,29 +5196,161 @@ "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "dependencies": { - "path-key": "^3.0.0" + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "node_modules/object.hasown": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", + "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", "dev": true, "dependencies": { - "boolbase": "^1.0.0" + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -3308,6 +5418,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -3535,6 +5662,51 @@ "node": ">=8" } }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/pretty-error": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", @@ -3551,6 +5723,17 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -3597,15 +5780,25 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, - "peer": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/range-parser": { "version": "1.2.1", @@ -3663,6 +5856,42 @@ "react": "^18.3.1" } }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "node_modules/react-router": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.24.1.tgz", + "integrity": "sha512-PTXFXGK2pyXpHzVo3rR9H7ip4lSPZZc0bHG5CARmj65fTT6qG7sTngmb6lcYu1gf3y/8KxORoy9yn59pGpCnpg==", + "dependencies": { + "@remix-run/router": "1.17.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.24.1.tgz", + "integrity": "sha512-U19KtXqooqw967Vw0Qcn5cOvrX5Ejo9ORmOtJMzYWtCT4/WOfFLIZGGsVLxcd9UkBO0mSTZtXqhZBsWlHr7+Sg==", + "dependencies": { + "@remix-run/router": "1.17.1", + "react-router": "6.24.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -3701,6 +5930,45 @@ "node": ">= 10.13.0" } }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/relateurl": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", @@ -3785,6 +6053,16 @@ "node": ">= 4" } }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rimraf": { "version": "5.0.9", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", @@ -3815,6 +6093,53 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -3835,6 +6160,23 @@ } ] }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -3928,16 +6270,6 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "peer": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", @@ -4033,6 +6365,21 @@ "node": ">= 0.4" } }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -4105,6 +6452,15 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -4220,6 +6576,18 @@ "node": ">= 0.8" } }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -4291,7 +6659,92 @@ "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/string.prototype.includes": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.0.tgz", + "integrity": "sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/strip-ansi": { @@ -4319,6 +6772,15 @@ "node": ">=8" } }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", @@ -4328,20 +6790,16 @@ "node": ">=6" } }, - "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -4356,6 +6814,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/synckit": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", + "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -4383,40 +6857,11 @@ "node": ">=10" } }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.10", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", - "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.20", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.26.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true }, "node_modules/thingies": { "version": "1.21.0", @@ -4473,6 +6918,18 @@ "tslib": "2" } }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, "node_modules/ts-loader": { "version": "9.5.1", "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", @@ -4502,12 +6959,36 @@ "node": ">= 8" } }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, "node_modules/tslib": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", "dev": true }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -4521,6 +7002,79 @@ "node": ">= 0.6" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typescript": { "version": "5.5.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", @@ -4534,6 +7088,69 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.16.0.tgz", + "integrity": "sha512-kaVRivQjOzuoCXU6+hLnjo3/baxyzWVO5GrnExkFzETRYJKVHYkrJglOu2OCm8Hi9RPDWX1PTNNTpU5KRV0+RA==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "7.16.0", + "@typescript-eslint/parser": "7.16.0", + "@typescript-eslint/utils": "7.16.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.0.tgz", + "integrity": "sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/typescript-estree": "7.16.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", @@ -4558,37 +7175,6 @@ "node": ">= 0.8" } }, - "node_modules/update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "peer": true, - "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -4637,20 +7223,6 @@ "node": ">= 0.8" } }, - "node_modules/watchpack": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", - "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", - "dev": true, - "peer": true, - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/wbuf": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", @@ -4660,54 +7232,6 @@ "minimalistic-assert": "^1.0.0" } }, - "node_modules/webpack": { - "version": "5.92.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.92.1.tgz", - "integrity": "sha512-JECQ7IwJb+7fgUFBlrJzbyu3GEuNBcdqr1LD7IbSzwkSmIevTm8PF+wej3Oxuz/JFBUZ6O1o43zsPkwm1C4TmA==", - "dev": true, - "peer": true, - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.5", - "@webassemblyjs/ast": "^1.12.1", - "@webassemblyjs/wasm-edit": "^1.12.1", - "@webassemblyjs/wasm-parser": "^1.12.1", - "acorn": "^8.7.1", - "acorn-import-attributes": "^1.9.5", - "browserslist": "^4.21.10", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.0", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.10", - "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, "node_modules/webpack-cli": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", @@ -4970,16 +7494,6 @@ "node": ">=10.0.0" } }, - "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", @@ -5018,12 +7532,106 @@ "node": ">= 8" } }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dev": true, + "dependencies": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/wildcard": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", "dev": true }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", @@ -5138,6 +7746,18 @@ "optional": true } } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/client/package.json b/client/package.json index 3f0fd4175..7546cdc62 100644 --- a/client/package.json +++ b/client/package.json @@ -5,24 +5,44 @@ "type": "module", "scripts": { "start": "webpack serve ", - "build": "webpack --mode production" + "build": "webpack --mode production", + "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'", + "format": "prettier --write 'src/**/*.{js,jsx,ts,tsx,json,css,scss,md}'" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { + "@eslint/compat": "^1.1.0", + "@eslint/js": "^9.6.0", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^7.16.0", + "@typescript-eslint/parser": "^7.16.0", + "eslint": "^9.6.0", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-jsx-a11y": "^6.9.0", + "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-react": "^7.34.3", + "eslint-plugin-react-hooks": "^4.6.2", "fork-ts-checker-webpack-plugin": "^9.0.2", + "globals": "^15.8.0", "html-loader": "^5.0.0", "html-webpack-plugin": "^5.6.0", + "prettier": "3.3.2", "ts-loader": "^9.5.1", "typescript": "^5.5.3", + "typescript-eslint": "^7.16.0", "webpack-cli": "^5.1.4", "webpack-dev-server": "^5.0.4" }, "dependencies": { "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "react-router-dom": "^6.24.1" + }, + "engines": { + "npm": ">=10.7.0", + "node": ">=20.15.1" } -} +} \ No newline at end of file diff --git a/client/src/App.tsx b/client/src/App.tsx index 243a74f3c..937325a99 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,9 +1,5 @@ -const App: React.FC = () =>{ - return( -
- Hello, React with Webpack -
- ); -} +const App: React.FC = () => { + return
Hello, React with Webpack
; +}; export default App; diff --git a/client/src/index.tsx b/client/src/index.tsx index c018515cd..e3791f790 100644 --- a/client/src/index.tsx +++ b/client/src/index.tsx @@ -3,7 +3,7 @@ import ReactDOM from 'react-dom/client'; import App from './App'; ReactDOM.createRoot(document.getElementById('root')!).render( - - - , + + + , ); diff --git a/client/tsconfig.json b/client/tsconfig.json index 5dfba11d7..c3bf098d3 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -1,44 +1,42 @@ { - "compilerOptions": { - "sourceMap": true, - "module": "ES2020", - "target": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "useDefineForClassFields": true, - "removeComments": true, - "skipLibCheck": true, - - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - - "jsx": "react-jsx", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true, + "compilerOptions": { + "sourceMap": true, + "module": "ES2020", + "target": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "useDefineForClassFields": true, + "removeComments": true, + "skipLibCheck": true, - "types": ["jest"], - "esModuleInterop": true, - "strictNullChecks": true, - "strictFunctionTypes": true, - "strictBindCallApply": true, - "strictPropertyInitialization": true, - "noImplicitAny": true, - "noImplicitThis": true, - "alwaysStrict": true, - "noImplicitReturns": true, - "forceConsistentCasingInFileNames": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, - "baseUrl": "./", - "paths": { - "components/*": [ - "src/components/*" - ], - }, - "outDir": "./dist" - }, - "include": ["src"], -} \ No newline at end of file + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + + "types": ["jest"], + "esModuleInterop": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictBindCallApply": true, + "strictPropertyInitialization": true, + "noImplicitAny": true, + "noImplicitThis": true, + "alwaysStrict": true, + "noImplicitReturns": true, + "forceConsistentCasingInFileNames": true, + + "baseUrl": "./", + "paths": { + "components/*": ["src/components/*"] + }, + "outDir": "./dist" + }, + "include": ["src"] +} diff --git a/client/webpack.config.js b/client/webpack.config.js index 9cc915a78..03798e534 100644 --- a/client/webpack.config.js +++ b/client/webpack.config.js @@ -1,38 +1,38 @@ import path from "path"; -import HtmlWebpackPlugin from 'html-webpack-plugin'; -import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; -import { fileURLToPath } from 'url'; +import HtmlWebpackPlugin from "html-webpack-plugin"; +import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin"; +import { fileURLToPath } from "url"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); export default { - mode: 'development', + mode: "development", entry: "./src/index.tsx", resolve: { extensions: [".js", ".jsx", ".ts", ".tsx"], }, - output: { + output: { path: path.join(__dirname, "dist"), filename: "bundle.min.js", }, module: { rules: [ - { + { test: /\.tsx?$/, - loader: 'ts-loader', + loader: "ts-loader", exclude: /node_modules/, - } - ] + }, + ], }, plugins: [ new HtmlWebpackPlugin({ - template: "./index.html" + template: "./index.html", }), new ForkTsCheckerWebpackPlugin(), ], devServer: { port: 3000, hot: true, - } -} \ No newline at end of file + }, +}; From 29a0a46e7d454756618f79c0a15fa819bea5817d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=90=E1=85=A2=E1=84=92=E1=85=AE?= =?UTF-8?q?=E1=86=AB?= Date: Thu, 11 Jul 2024 17:25:53 +0900 Subject: [PATCH 003/178] =?UTF-8?q?docs:=20pr=20=ED=85=9C=ED=94=8C?= =?UTF-8?q?=EB=A6=BF=20=EB=B0=8F=20issue=20=ED=85=9C=ED=94=8C=EB=A6=BF=20?= =?UTF-8?q?=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe , soi-ha , jinhokim98 --- .github/ISSUE_TEMPLATE/bug-template.md | 10 ++++++++++ .github/ISSUE_TEMPLATE/feature-template.md | 9 +++++++++ .github/pull-request-template.md | 13 +++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-template.md create mode 100644 .github/ISSUE_TEMPLATE/feature-template.md create mode 100644 .github/pull-request-template.md diff --git a/.github/ISSUE_TEMPLATE/bug-template.md b/.github/ISSUE_TEMPLATE/bug-template.md new file mode 100644 index 000000000..1a8d6a0d0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-template.md @@ -0,0 +1,10 @@ +## 📄 버그 내용 +어떤 버그인지 간결하게 설명해주세요. + +## 🚨 버그 발생 상황 +최대한 상세하게 작성해주세요. + +## 예상 결과 +예상했던 정상적인 결과가 어떤 것인지 설명해주세요. + +## 🫡 참고사항 diff --git a/.github/ISSUE_TEMPLATE/feature-template.md b/.github/ISSUE_TEMPLATE/feature-template.md new file mode 100644 index 000000000..76b8b47be --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-template.md @@ -0,0 +1,9 @@ +## 📄 설명 + +추가하려는 기능에 대해 간결하게 설명해주세요. + +## 🏁 할 일 + +- [ ] 예상되는 작업을 상세하게 작성해주세요. (checkBox 형태로 작성해주세요.) + +## 🫡 참고사항 diff --git a/.github/pull-request-template.md b/.github/pull-request-template.md new file mode 100644 index 000000000..863663bb0 --- /dev/null +++ b/.github/pull-request-template.md @@ -0,0 +1,13 @@ +## issue +- close #n + +## 구현 사항 +어떤 것을 구현했는지 필요히다면 사진 || 영상과 함께 자세히 설명해주세요. + +## 중점적으로 리뷰받고 싶은 부분(선택) +어떤 부분을 중점으로 리뷰했으면 좋겠는지 작성해주세요. + +## 논의하고 싶은 부분(선택) +논의하고 싶은 부분이 있다면 작성해주세요. + +## 🫡 참고사항 From 4ac4d93f0ecd5005b07927e424c4a48c383244d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=90=E1=85=A2=E1=84=92=E1=85=AE?= =?UTF-8?q?=E1=86=AB?= Date: Thu, 11 Jul 2024 17:47:30 +0900 Subject: [PATCH 004/178] =?UTF-8?q?docs:=20issue=20=ED=85=9C=ED=94=8C?= =?UTF-8?q?=EB=A6=BF=EC=97=90=20=ED=83=80=EC=9D=B4=ED=8B=80=EA=B3=BC=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=EB=90=9C=20=EB=B6=80=EA=B0=80=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe , soi-ha , jinhokim98 --- .github/ISSUE_TEMPLATE/bug-template.md | 8 ++++++++ .github/ISSUE_TEMPLATE/feature-template.md | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug-template.md b/.github/ISSUE_TEMPLATE/bug-template.md index 1a8d6a0d0..e14ce93b3 100644 --- a/.github/ISSUE_TEMPLATE/bug-template.md +++ b/.github/ISSUE_TEMPLATE/bug-template.md @@ -1,3 +1,11 @@ +--- +name: Bug Template +about: 버그를 제보하는 템플릿 +title: "" +labels: 🚨bug +assignees: '' +--- + ## 📄 버그 내용 어떤 버그인지 간결하게 설명해주세요. diff --git a/.github/ISSUE_TEMPLATE/feature-template.md b/.github/ISSUE_TEMPLATE/feature-template.md index 76b8b47be..d29aa8e98 100644 --- a/.github/ISSUE_TEMPLATE/feature-template.md +++ b/.github/ISSUE_TEMPLATE/feature-template.md @@ -1,3 +1,11 @@ +--- +name: Feature Template +about: 기능에 관한 템플릿 +title: "" +labels: ⚙️ feat +assignees: '' +--- + ## 📄 설명 추가하려는 기능에 대해 간결하게 설명해주세요. From c4a8dc16ae255273e4b1ecae8fbd7f2122ed6c80 Mon Sep 17 00:00:00 2001 From: pakxe Date: Mon, 15 Jul 2024 20:34:38 +0900 Subject: [PATCH 005/178] =?UTF-8?q?chore:=20=EB=AA=A8=EB=93=A0=20install?= =?UTF-8?q?=20=EC=97=90=20legacy-peer-deps=EB=A5=BC=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari --- client/.npmrc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/.npmrc b/client/.npmrc index d1cdf2f06..ece05f588 100644 --- a/client/.npmrc +++ b/client/.npmrc @@ -1 +1,2 @@ -engine-strict = true \ No newline at end of file +engine-strict = true +legacy-peer-deps = true From 404c8c525b91a718c89e20405aededa4b31364bf Mon Sep 17 00:00:00 2001 From: pakxe Date: Mon, 15 Jul 2024 20:35:38 +0900 Subject: [PATCH 006/178] =?UTF-8?q?chore:=20emotion=20css=20props=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=20=EC=98=88=EC=A0=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari --- client/src/App.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/client/src/App.tsx b/client/src/App.tsx index 937325a99..b5b756a36 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,5 +1,12 @@ +import {css} from '@emotion/react'; + +// 테스트 css props 사용 예제입니다. 추후 삭제 예정 +const style = css` + color: red; +`; + const App: React.FC = () => { - return
Hello, React with Webpack
; + return
Hello, React with Webpack
; }; export default App; From 6eb4bb5ec624c070ebfc7eb9066819336fa9587a Mon Sep 17 00:00:00 2001 From: pakxe Date: Mon, 15 Jul 2024 20:36:39 +0900 Subject: [PATCH 007/178] =?UTF-8?q?chore:=20webpack,=20@emotion/react=20?= =?UTF-8?q?=EB=9D=BC=EC=9D=B4=EB=B8=8C=EB=9F=AC=EB=A6=AC=20=EC=84=A4?= =?UTF-8?q?=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari --- client/package-lock.json | 16390 +++++++++++++++++++------------------ client/package.json | 96 +- 2 files changed, 8678 insertions(+), 7808 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index bd52102a9..aced154c7 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1,7763 +1,8631 @@ { - "name": "haengdong-client", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "haengdong-client", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "react": "^18.3.1", - "react-dom": "^18.3.1", - "react-router-dom": "^6.24.1" - }, - "devDependencies": { - "@eslint/compat": "^1.1.0", - "@eslint/js": "^9.6.0", - "@types/react": "^18.3.3", - "@types/react-dom": "^18.3.0", - "@typescript-eslint/eslint-plugin": "^7.16.0", - "@typescript-eslint/parser": "^7.16.0", - "eslint": "^9.6.0", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jsx-a11y": "^6.9.0", - "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-react": "^7.34.3", - "eslint-plugin-react-hooks": "^4.6.2", - "fork-ts-checker-webpack-plugin": "^9.0.2", - "globals": "^15.8.0", - "html-loader": "^5.0.0", - "html-webpack-plugin": "^5.6.0", - "prettier": "3.3.2", - "ts-loader": "^9.5.1", - "typescript": "^5.5.3", - "typescript-eslint": "^7.16.0", - "webpack-cli": "^5.1.4", - "webpack-dev-server": "^5.0.4" - }, - "engines": { - "node": ">=20.15.1", - "npm": ">=10.7.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.24.7", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", - "dev": true, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", - "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/compat": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.1.0.tgz", - "integrity": "sha512-s9Wi/p25+KbzxKlDm3VshQdImhWk+cbdblhwGNnyCU5lpSwtWa4v7VQCxSki0FAUrGA3s8nCWgYzAH41mwQVKQ==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.0.tgz", - "integrity": "sha512-A68TBu6/1mHHuc5YJL0U0VVeGNiklLAL6rRmhTCP2B5XjWLMnrX+HkO+IAXyHvks5cyyY1jjK5ITPQ1HGS2EVA==", - "dev": true, - "dependencies": { - "@eslint/object-schema": "^2.1.4", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/config-array/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/config-array/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@eslint/eslintrc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@eslint/js": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.6.0.tgz", - "integrity": "sha512-D9B0/3vNg44ZeWbYMpBoXqNP4j6eQD5vNwIlGAuFRRzK/WtT/jvDQW3Bi9kkf3PMDMlM7Yi+73VLUsn5bJcl8A==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", - "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", - "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", - "dev": true, - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@jsonjoy.com/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", - "dev": true, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/json-pack": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.0.4.tgz", - "integrity": "sha512-aOcSN4MeAtFROysrbqG137b7gaDDSmVrl5mpo6sT/w+kcXpWnzhMjmY/Fh/sDx26NBxyIE7MB1seqLeCAzy9Sg==", - "dev": true, - "dependencies": { - "@jsonjoy.com/base64": "^1.1.1", - "@jsonjoy.com/util": "^1.1.2", - "hyperdyperid": "^1.2.0", - "thingies": "^1.20.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/util": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.2.0.tgz", - "integrity": "sha512-4B8B+3vFsY4eo33DMKyJPlQ3sBMpPFUZK2dr3O3rXrOGKKbYG44J0XSFkDo1VOQiri5HFEhIeVvItjR2xcazmg==", - "dev": true, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", - "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", - "dev": true - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/@remix-run/router": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.17.1.tgz", - "integrity": "sha512-mCOMec4BKd6BRGBZeSnGiIgwsbLGp3yhVqAD8H+PxiRNEHgDpZb8J1TnrSDlg97t0ySKMQJTHCWBCmBpSmkF6Q==", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", - "dev": true, - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/bonjour": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", - "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect-history-api-fallback": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", - "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", - "dev": true, - "dependencies": { - "@types/express-serve-static-core": "*", - "@types/node": "*" - } - }, - "node_modules/@types/express": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", - "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", - "dev": true, - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.19.5", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", - "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", - "dev": true - }, - "node_modules/@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true - }, - "node_modules/@types/http-proxy": { - "version": "1.17.14", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", - "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true - }, - "node_modules/@types/node": { - "version": "20.14.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", - "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/node-forge": { - "version": "1.3.11", - "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", - "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/prop-types": { - "version": "15.7.12", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "dev": true - }, - "node_modules/@types/qs": { - "version": "6.9.15", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", - "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", - "dev": true - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true - }, - "node_modules/@types/react": { - "version": "18.3.3", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", - "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", - "dev": true, - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", - "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", - "dev": true, - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/retry": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", - "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", - "dev": true - }, - "node_modules/@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", - "dev": true, - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/serve-index": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", - "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", - "dev": true, - "dependencies": { - "@types/express": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.7", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", - "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", - "dev": true, - "dependencies": { - "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "*" - } - }, - "node_modules/@types/sockjs": { - "version": "0.3.36", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", - "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/ws": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.16.0.tgz", - "integrity": "sha512-py1miT6iQpJcs1BiJjm54AMzeuMPBSPuKPlnT8HlfudbcS5rYeX5jajpLf3mrdRh9dA/Ec2FVUY0ifeVNDIhZw==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.16.0", - "@typescript-eslint/type-utils": "7.16.0", - "@typescript-eslint/utils": "7.16.0", - "@typescript-eslint/visitor-keys": "7.16.0", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.16.0.tgz", - "integrity": "sha512-j0fuUswUjDHfqV/UdW6mLtOQQseORqfdmoBNDFOqs9rvNVR2e+cmu6zJu/Ku4SDuqiJko6YnhwcL8x45r8Oqxg==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "7.16.0", - "@typescript-eslint/utils": "7.16.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.0.tgz", - "integrity": "sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.16.0", - "@typescript-eslint/types": "7.16.0", - "@typescript-eslint/typescript-estree": "7.16.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@typescript-eslint/parser": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.16.0.tgz", - "integrity": "sha512-ar9E+k7CU8rWi2e5ErzQiC93KKEFAXA2Kky0scAlPcxYblLt8+XZuHUZwlyfXILyQa95P6lQg+eZgh/dDs3+Vw==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "7.16.0", - "@typescript-eslint/types": "7.16.0", - "@typescript-eslint/typescript-estree": "7.16.0", - "@typescript-eslint/visitor-keys": "7.16.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.16.0.tgz", - "integrity": "sha512-8gVv3kW6n01Q6TrI1cmTZ9YMFi3ucDT7i7aI5lEikk2ebk1AEjrwX8MDTdaX5D7fPXMBLvnsaa0IFTAu+jcfOw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.16.0", - "@typescript-eslint/visitor-keys": "7.16.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.16.0.tgz", - "integrity": "sha512-fecuH15Y+TzlUutvUl9Cc2XJxqdLr7+93SQIbcZfd4XRGGKoxyljK27b+kxKamjRkU7FYC6RrbSCg0ALcZn/xw==", - "dev": true, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.16.0.tgz", - "integrity": "sha512-a5NTvk51ZndFuOLCh5OaJBELYc2O3Zqxfl3Js78VFE1zE46J2AaVuW+rEbVkQznjkmlzWsUI15BG5tQMixzZLw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.16.0", - "@typescript-eslint/visitor-keys": "7.16.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.16.0.tgz", - "integrity": "sha512-rMo01uPy9C7XxG7AFsxa8zLnWXTF8N3PYclekWSrurvhwiw1eW88mrKiAYe6s53AUY57nTRz8dJsuuXdkAhzCg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.16.0", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@webpack-cli/configtest": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", - "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", - "dev": true, - "engines": { - "node": ">=14.15.0" - }, - "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" - } - }, - "node_modules/@webpack-cli/info": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", - "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", - "dev": true, - "engines": { - "node": ">=14.15.0" - }, - "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" - } - }, - "node_modules/@webpack-cli/serve": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", - "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", - "dev": true, - "engines": { - "node": ">=14.15.0" - }, - "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" - }, - "peerDependenciesMeta": { - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", - "dev": true, - "engines": [ - "node >= 0.8.0" - ], - "bin": { - "ansi-html": "bin/ansi-html" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "dev": true, - "dependencies": { - "deep-equal": "^2.0.5" - } - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true - }, - "node_modules/array-includes": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", - "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array.prototype.findlast": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", - "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", - "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.toreversed": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", - "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - } - }, - "node_modules/array.prototype.tosorted": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", - "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", - "es-errors": "^1.3.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/ast-types-flow": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", - "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", - "dev": true - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dev": true, - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/axe-core": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.9.1.tgz", - "integrity": "sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/axobject-query": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", - "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", - "dev": true, - "dependencies": { - "deep-equal": "^2.0.5" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", - "dev": true, - "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.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/bonjour-service": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", - "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "multicast-dns": "^7.2.5" - } - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/bundle-name": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", - "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", - "dev": true, - "dependencies": { - "run-applescript": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", - "dev": true, - "dependencies": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/clean-css": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", - "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", - "dev": true, - "dependencies": { - "source-map": "~0.6.0" - }, - "engines": { - "node": ">= 10.0" - } - }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "dev": true, - "dependencies": { - "mime-db": ">= 1.43.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", - "dev": true, - "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/compression/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/connect-history-api-fallback": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", - "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dev": true, - "dependencies": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css-select": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "dev": true, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true - }, - "node_modules/damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", - "dev": true - }, - "node_modules/data-view-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", - "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", - "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", - "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/deep-equal": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", - "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.5", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.2", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.2", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/deep-equal/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-browser": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", - "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", - "dev": true, - "dependencies": { - "bundle-name": "^4.1.0", - "default-browser-id": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser-id": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", - "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-gateway": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", - "dev": true, - "dependencies": { - "execa": "^5.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-lazy-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", - "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dns-packet": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", - "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", - "dev": true, - "dependencies": { - "@leichtgewicht/ip-codec": "^2.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", - "dev": true, - "dependencies": { - "utila": "~0.4" - } - }, - "node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "dev": true, - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "dev": true, - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "dev": true, - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", - "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/envinfo": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", - "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", - "dev": true, - "bin": { - "envinfo": "dist/cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.23.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", - "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "data-view-buffer": "^1.0.1", - "data-view-byte-length": "^1.0.1", - "data-view-byte-offset": "^1.0.0", - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-set-tostringtag": "^2.0.3", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "hasown": "^2.0.2", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.1", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.2", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.9", - "string.prototype.trimend": "^1.0.8", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.6", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.15" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-get-iterator/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/es-iterator-helpers": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", - "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", - "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.3", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.7", - "iterator.prototype": "^1.1.2", - "safe-array-concat": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", - "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.6.0.tgz", - "integrity": "sha512-ElQkdLMEEqQNM9Njff+2Y4q2afHk7JpkPvrd7Xh7xefwgQynqPxwf55J7di9+MEibWUGdNjFF9ITG9Pck5M84w==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/config-array": "^0.17.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.6.0", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.3.0", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.0.1", - "eslint-visitor-keys": "^4.0.0", - "espree": "^10.1.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "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" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/eslint-module-utils": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", - "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", - "dev": true, - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/eslint-plugin-import": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", - "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", - "object.values": "^1.1.7", - "semver": "^6.3.1", - "tsconfig-paths": "^3.15.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.9.0.tgz", - "integrity": "sha512-nOFOCaJG2pYqORjK19lqPqxMO/JpvdCZdPtNdxY3kvom3jTvkAbOvQvD8wuD0G8BYR0IGAGYDlzqWJOh/ybn2g==", - "dev": true, - "dependencies": { - "aria-query": "~5.1.3", - "array-includes": "^3.1.8", - "array.prototype.flatmap": "^1.3.2", - "ast-types-flow": "^0.0.8", - "axe-core": "^4.9.1", - "axobject-query": "~3.1.1", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "es-iterator-helpers": "^1.0.19", - "hasown": "^2.0.2", - "jsx-ast-utils": "^3.3.5", - "language-tags": "^1.0.9", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "safe-regex-test": "^1.0.3", - "string.prototype.includes": "^2.0.0" - }, - "engines": { - "node": ">=4.0" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", - "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", - "dev": true, - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.8.6" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "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 - } - } - }, - "node_modules/eslint-plugin-react": { - "version": "7.34.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.3.tgz", - "integrity": "sha512-aoW4MV891jkUulwDApQbPYTVZmeuSyFrudpbTAQuj5Fv8VL+o6df2xIGpw8B0hPjAaih1/Fb0om9grCdyFYemA==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.8", - "array.prototype.findlast": "^1.2.5", - "array.prototype.flatmap": "^1.3.2", - "array.prototype.toreversed": "^1.1.2", - "array.prototype.tosorted": "^1.1.4", - "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.19", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.8", - "object.fromentries": "^2.0.8", - "object.hasown": "^1.1.4", - "object.values": "^1.2.0", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.5", - "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.11" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", - "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/eslint-plugin-react/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-react/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint-plugin-react/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/eslint-plugin-react/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.1.tgz", - "integrity": "sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", - "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/espree": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", - "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", - "dev": true, - "dependencies": { - "acorn": "^8.12.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", - "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", - "dev": true, - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.2", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.6.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" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "dev": true, - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "dev": true, - "dependencies": { - "websocket-driver": ">=0.5.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dev": true, - "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" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/foreground-child": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", - "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/fork-ts-checker-webpack-plugin": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-9.0.2.tgz", - "integrity": "sha512-Uochze2R8peoN1XqlSi/rGUkDQpRogtLFocP9+PGu68zk1BDAKXfdeCdyVZpgTk8V8WFVQXdEz426VKjXLO1Gg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.7", - "chalk": "^4.1.2", - "chokidar": "^3.5.3", - "cosmiconfig": "^8.2.0", - "deepmerge": "^4.2.2", - "fs-extra": "^10.0.0", - "memfs": "^3.4.1", - "minimatch": "^3.0.4", - "node-abort-controller": "^3.0.1", - "schema-utils": "^3.1.1", - "semver": "^7.3.5", - "tapable": "^2.2.1" - }, - "engines": { - "node": ">=12.13.0", - "yarn": ">=1.0.0" - }, - "peerDependencies": { - "typescript": ">3.6.0", - "webpack": "^5.11.0" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/memfs": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", - "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", - "dev": true, - "dependencies": { - "fs-monkey": "^1.0.4" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/fs-monkey": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", - "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globals": { - "version": "15.8.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.8.0.tgz", - "integrity": "sha512-VZAJ4cewHTExBWDHR6yptdIBlx9YSSZuwojj9Nt5mBRXQzrKakDsVKQ1J63sklLvzAJm0X5+RpO4i3Y2hcOnFw==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "node_modules/hpack.js/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/hpack.js/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/hpack.js/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/html-entities": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", - "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/mdevils" - }, - { - "type": "patreon", - "url": "https://patreon.com/mdevils" - } - ] - }, - "node_modules/html-loader": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-5.0.0.tgz", - "integrity": "sha512-puaGKdjdVVIFRtgIC2n5dt5bt0N5j6heXlAQZ4Do1MLjHmOT1gCE1Ogg7XZNeJlnOVHHsrZKGs5dfh+XwZ3XPw==", - "dev": true, - "dependencies": { - "html-minifier-terser": "^7.2.0", - "parse5": "^7.1.2" - }, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/html-loader/node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "dev": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/html-loader/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/html-loader/node_modules/html-minifier-terser": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", - "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", - "dev": true, - "dependencies": { - "camel-case": "^4.1.2", - "clean-css": "~5.3.2", - "commander": "^10.0.0", - "entities": "^4.4.0", - "param-case": "^3.0.4", - "relateurl": "^0.2.7", - "terser": "^5.15.1" - }, - "bin": { - "html-minifier-terser": "cli.js" - }, - "engines": { - "node": "^14.13.1 || >=16.0.0" - } - }, - "node_modules/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", - "dev": true, - "dependencies": { - "camel-case": "^4.1.2", - "clean-css": "^5.2.2", - "commander": "^8.3.0", - "he": "^1.2.0", - "param-case": "^3.0.4", - "relateurl": "^0.2.7", - "terser": "^5.10.0" - }, - "bin": { - "html-minifier-terser": "cli.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/html-minifier-terser/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/html-webpack-plugin": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", - "integrity": "sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==", - "dev": true, - "dependencies": { - "@types/html-minifier-terser": "^6.0.0", - "html-minifier-terser": "^6.0.2", - "lodash": "^4.17.21", - "pretty-error": "^4.0.0", - "tapable": "^2.0.0" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/html-webpack-plugin" - }, - "peerDependencies": { - "@rspack/core": "0.x || 1.x", - "webpack": "^5.20.0" - }, - "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - }, - "webpack": { - "optional": true - } - } - }, - "node_modules/htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "node_modules/http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-parser-js": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", - "dev": true - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", - "dev": true, - "dependencies": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@types/express": "^4.17.13" - }, - "peerDependenciesMeta": { - "@types/express": { - "optional": true - } - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/hyperdyperid": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", - "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", - "dev": true, - "engines": { - "node": ">=10.18" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/interpret": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", - "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", - "dev": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/ipaddr.js": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", - "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-async-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", - "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", - "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", - "dev": true, - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-view": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", - "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", - "dev": true, - "dependencies": { - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", - "dev": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-finalizationregistry": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", - "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-inside-container": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", - "dev": true, - "dependencies": { - "is-docker": "^3.0.0" - }, - "bin": { - "is-inside-container": "cli.js" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-network-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", - "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", - "dev": true, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", - "dev": true, - "dependencies": { - "which-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", - "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-wsl": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", - "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", - "dev": true, - "dependencies": { - "is-inside-container": "^1.0.0" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/iterator.prototype": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", - "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "reflect.getprototypeof": "^1.0.4", - "set-function-name": "^2.0.1" - } - }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsx-ast-utils": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", - "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/language-subtag-registry": { - "version": "0.3.23", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", - "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", - "dev": true - }, - "node_modules/language-tags": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", - "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", - "dev": true, - "dependencies": { - "language-subtag-registry": "^0.3.20" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/launch-editor": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.0.tgz", - "integrity": "sha512-vJranOAJrI/llyWGRQqiDM+adrw+k83fvmmx3+nV47g3+36xM15jE+zyZ6Ffel02+xSvuM0b2GDRosXZkbb6wA==", - "dev": true, - "dependencies": { - "picocolors": "^1.0.0", - "shell-quote": "^1.8.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dev": true, - "dependencies": { - "tslib": "^2.0.3" - } - }, - "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memfs": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.9.3.tgz", - "integrity": "sha512-bsYSSnirtYTWi1+OPMFb0M048evMKyUYe0EbtuGQgq6BVQM1g1W8/KIUJCCvjgI/El0j6Q4WsmMiBwLUBSw8LA==", - "dev": true, - "dependencies": { - "@jsonjoy.com/json-pack": "^1.0.3", - "@jsonjoy.com/util": "^1.1.2", - "tree-dump": "^1.0.1", - "tslib": "^2.0.0" - }, - "engines": { - "node": ">= 4.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", - "dev": true, - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", - "dev": true, - "dependencies": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" - }, - "bin": { - "multicast-dns": "cli.js" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dev": true, - "dependencies": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - } - }, - "node_modules/node-abort-controller": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", - "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", - "dev": true - }, - "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", - "dev": true, - "engines": { - "node": ">= 6.13.0" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-is": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", - "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", - "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", - "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.groupby": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", - "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.hasown": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", - "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.values": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", - "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/open": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", - "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", - "dev": true, - "dependencies": { - "default-browser": "^5.2.1", - "define-lazy-prop": "^3.0.0", - "is-inside-container": "^1.0.0", - "is-wsl": "^3.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-retry": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz", - "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==", - "dev": true, - "dependencies": { - "@types/retry": "0.12.2", - "is-network-error": "^1.0.0", - "retry": "^0.13.1" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", - "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", - "dev": true - }, - "node_modules/param-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", - "dev": true, - "dependencies": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dev": true, - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/pascal-case": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", - "dev": true, - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", - "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/pretty-error": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", - "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", - "dev": true, - "dependencies": { - "lodash": "^4.17.20", - "renderkid": "^3.0.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-addr/node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "dev": true, - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/raw-body/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - }, - "node_modules/react-router": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.24.1.tgz", - "integrity": "sha512-PTXFXGK2pyXpHzVo3rR9H7ip4lSPZZc0bHG5CARmj65fTT6qG7sTngmb6lcYu1gf3y/8KxORoy9yn59pGpCnpg==", - "dependencies": { - "@remix-run/router": "1.17.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8" - } - }, - "node_modules/react-router-dom": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.24.1.tgz", - "integrity": "sha512-U19KtXqooqw967Vw0Qcn5cOvrX5Ejo9ORmOtJMzYWtCT4/WOfFLIZGGsVLxcd9UkBO0mSTZtXqhZBsWlHr7+Sg==", - "dependencies": { - "@remix-run/router": "1.17.1", - "react-router": "6.24.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/rechoir": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", - "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", - "dev": true, - "dependencies": { - "resolve": "^1.20.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", - "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.1", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", - "which-builtin-type": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/renderkid": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", - "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", - "dev": true, - "dependencies": { - "css-select": "^4.1.3", - "dom-converter": "^0.2.0", - "htmlparser2": "^6.1.0", - "lodash": "^4.17.21", - "strip-ansi": "^6.0.1" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", - "integrity": "sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==", - "dev": true, - "dependencies": { - "glob": "^10.3.7" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "engines": { - "node": "14 >=14.20 || 16 >=16.20 || >=18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-applescript": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", - "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-array-concat": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", - "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-array-concat/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safe-regex-test": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-regex": "^1.1.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true - }, - "node_modules/selfsigned": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", - "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", - "dev": true, - "dependencies": { - "@types/node-forge": "^1.3.0", - "node-forge": "^1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dev": true, - "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" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", - "dev": true, - "dependencies": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/serve-index/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-index/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", - "dev": true, - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-index/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true - }, - "node_modules/serve-index/node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true - }, - "node_modules/serve-index/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dev": true, - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/sockjs": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", - "dev": true, - "dependencies": { - "faye-websocket": "^0.11.3", - "uuid": "^8.3.2", - "websocket-driver": "^0.7.4" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", - "dev": true, - "dependencies": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "dev": true, - "dependencies": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - } - }, - "node_modules/spdy-transport/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/spdy-transport/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/spdy/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/spdy/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "dev": true, - "dependencies": { - "internal-slot": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/string.prototype.includes": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.0.tgz", - "integrity": "sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "node_modules/string.prototype.matchall": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", - "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.7", - "regexp.prototype.flags": "^1.5.2", - "set-function-name": "^2.0.2", - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", - "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", - "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/synckit": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", - "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", - "dev": true, - "dependencies": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/terser": { - "version": "5.31.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.2.tgz", - "integrity": "sha512-LGyRZVFm/QElZHy/CPr/O4eNZOZIzsrQ92y4v9UJe/pFJjypje2yI3C2FmPtvUEnhadlSbmG2nXtdcjHOjCfxw==", - "dev": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/thingies": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", - "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", - "dev": true, - "engines": { - "node": ">=10.18" - }, - "peerDependencies": { - "tslib": "^2" - } - }, - "node_modules/thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tree-dump": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", - "integrity": "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==", - "dev": true, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", - "dev": true, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/ts-loader": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", - "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "enhanced-resolve": "^5.0.0", - "micromatch": "^4.0.0", - "semver": "^7.3.4", - "source-map": "^0.7.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "typescript": "*", - "webpack": "^5.0.0" - } - }, - "node_modules/ts-loader/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", - "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typescript": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", - "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.16.0.tgz", - "integrity": "sha512-kaVRivQjOzuoCXU6+hLnjo3/baxyzWVO5GrnExkFzETRYJKVHYkrJglOu2OCm8Hi9RPDWX1PTNNTpU5KRV0+RA==", - "dev": true, - "dependencies": { - "@typescript-eslint/eslint-plugin": "7.16.0", - "@typescript-eslint/parser": "7.16.0", - "@typescript-eslint/utils": "7.16.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.0.tgz", - "integrity": "sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.16.0", - "@typescript-eslint/types": "7.16.0", - "@typescript-eslint/typescript-estree": "7.16.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/utila": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", - "dev": true - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "dev": true, - "dependencies": { - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/webpack-cli": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", - "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", - "dev": true, - "dependencies": { - "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^2.1.1", - "@webpack-cli/info": "^2.0.2", - "@webpack-cli/serve": "^2.0.5", - "colorette": "^2.0.14", - "commander": "^10.0.1", - "cross-spawn": "^7.0.3", - "envinfo": "^7.7.3", - "fastest-levenshtein": "^1.0.12", - "import-local": "^3.0.2", - "interpret": "^3.1.1", - "rechoir": "^0.8.0", - "webpack-merge": "^5.7.3" - }, - "bin": { - "webpack-cli": "bin/cli.js" - }, - "engines": { - "node": ">=14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "5.x.x" - }, - "peerDependenciesMeta": { - "@webpack-cli/generators": { - "optional": true - }, - "webpack-bundle-analyzer": { - "optional": true - }, - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/webpack-cli/node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "dev": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/webpack-dev-middleware": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.2.1.tgz", - "integrity": "sha512-hRLz+jPQXo999Nx9fXVdKlg/aehsw1ajA9skAneGmT03xwmyuhvF93p6HUKKbWhXdcERtGTzUCtIQr+2IQegrA==", - "dev": true, - "dependencies": { - "colorette": "^2.0.10", - "memfs": "^4.6.0", - "mime-types": "^2.1.31", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - } - } - }, - "node_modules/webpack-dev-middleware/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/webpack-dev-middleware/node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/webpack-dev-server": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.0.4.tgz", - "integrity": "sha512-dljXhUgx3HqKP2d8J/fUMvhxGhzjeNVarDLcbO/EWMSgRizDkxHQDZQaLFL5VJY9tRBj2Gz+rvCEYYvhbqPHNA==", - "dev": true, - "dependencies": { - "@types/bonjour": "^3.5.13", - "@types/connect-history-api-fallback": "^1.5.4", - "@types/express": "^4.17.21", - "@types/serve-index": "^1.9.4", - "@types/serve-static": "^1.15.5", - "@types/sockjs": "^0.3.36", - "@types/ws": "^8.5.10", - "ansi-html-community": "^0.0.8", - "bonjour-service": "^1.2.1", - "chokidar": "^3.6.0", - "colorette": "^2.0.10", - "compression": "^1.7.4", - "connect-history-api-fallback": "^2.0.0", - "default-gateway": "^6.0.3", - "express": "^4.17.3", - "graceful-fs": "^4.2.6", - "html-entities": "^2.4.0", - "http-proxy-middleware": "^2.0.3", - "ipaddr.js": "^2.1.0", - "launch-editor": "^2.6.1", - "open": "^10.0.3", - "p-retry": "^6.2.0", - "rimraf": "^5.0.5", - "schema-utils": "^4.2.0", - "selfsigned": "^2.4.1", - "serve-index": "^1.9.1", - "sockjs": "^0.3.24", - "spdy": "^4.0.2", - "webpack-dev-middleware": "^7.1.0", - "ws": "^8.16.0" - }, - "bin": { - "webpack-dev-server": "bin/webpack-dev-server.js" - }, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - }, - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-dev-server/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack-dev-server/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/webpack-dev-server/node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/webpack-merge": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", - "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", - "dev": true, - "dependencies": { - "clone-deep": "^4.0.1", - "flat": "^5.0.2", - "wildcard": "^2.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "dev": true, - "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", - "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", - "dev": true, - "dependencies": { - "function.prototype.name": "^1.1.5", - "has-tostringtag": "^1.0.0", - "is-async-function": "^2.0.0", - "is-date-object": "^1.0.5", - "is-finalizationregistry": "^1.0.2", - "is-generator-function": "^1.0.10", - "is-regex": "^1.1.4", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/which-collection": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", - "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", - "dev": true, - "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/wildcard": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", - "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", - "dev": true - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } + "name": "haengdong-client", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "haengdong-client", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@emotion/react": "^11.11.4", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.24.1" + }, + "devDependencies": { + "@eslint/compat": "^1.1.0", + "@eslint/js": "^9.6.0", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^7.16.0", + "@typescript-eslint/parser": "^7.16.0", + "eslint": "^9.6.0", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-jsx-a11y": "^6.9.0", + "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-react": "^7.34.3", + "eslint-plugin-react-hooks": "^4.6.2", + "fork-ts-checker-webpack-plugin": "^9.0.2", + "globals": "^15.8.0", + "html-loader": "^5.0.0", + "html-webpack-plugin": "^5.6.0", + "prettier": "3.3.2", + "ts-loader": "^9.5.1", + "typescript": "^5.5.3", + "typescript-eslint": "^7.16.0", + "webpack": "^5.93.0", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^5.0.4" + }, + "engines": { + "node": ">=20.15.1", + "npm": ">=10.7.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.9.tgz", + "integrity": "sha512-G8v3jRg+z8IwY1jHFxvCNhOPYPterE4XljNgdGTYfSTtzzwjIswIzIaSPSLs3R7yFuqnqNeay5rjICfqVr+/6A==", + "dependencies": { + "@babel/types": "^7.24.9", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", + "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", + "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", + "dependencies": { + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", + "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", + "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", + "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", + "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz", + "integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.8", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/parser": "^7.24.8", + "@babel/types": "^7.24.8", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/traverse/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@babel/types": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.9.tgz", + "integrity": "sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==", + "dependencies": { + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", + "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/serialize": "^1.1.2", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "dependencies": { + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", + "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + }, + "node_modules/@emotion/react": { + "version": "11.11.4", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.4.tgz", + "integrity": "sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/cache": "^11.11.0", + "@emotion/serialize": "^1.1.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.4.tgz", + "integrity": "sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ==", + "dependencies": { + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/unitless": "^0.8.1", + "@emotion/utils": "^1.2.1", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" + }, + "node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", + "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/compat": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.1.0.tgz", + "integrity": "sha512-s9Wi/p25+KbzxKlDm3VshQdImhWk+cbdblhwGNnyCU5lpSwtWa4v7VQCxSki0FAUrGA3s8nCWgYzAH41mwQVKQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.0.tgz", + "integrity": "sha512-A68TBu6/1mHHuc5YJL0U0VVeGNiklLAL6rRmhTCP2B5XjWLMnrX+HkO+IAXyHvks5cyyY1jjK5ITPQ1HGS2EVA==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-array/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@eslint/js": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.6.0.tgz", + "integrity": "sha512-D9B0/3vNg44ZeWbYMpBoXqNP4j6eQD5vNwIlGAuFRRzK/WtT/jvDQW3Bi9kkf3PMDMlM7Yi+73VLUsn5bJcl8A==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", + "dev": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.0.4.tgz", + "integrity": "sha512-aOcSN4MeAtFROysrbqG137b7gaDDSmVrl5mpo6sT/w+kcXpWnzhMjmY/Fh/sDx26NBxyIE7MB1seqLeCAzy9Sg==", + "dev": true, + "dependencies": { + "@jsonjoy.com/base64": "^1.1.1", + "@jsonjoy.com/util": "^1.1.2", + "hyperdyperid": "^1.2.0", + "thingies": "^1.20.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.2.0.tgz", + "integrity": "sha512-4B8B+3vFsY4eo33DMKyJPlQ3sBMpPFUZK2dr3O3rXrOGKKbYG44J0XSFkDo1VOQiri5HFEhIeVvItjR2xcazmg==", + "dev": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@remix-run/router": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.17.1.tgz", + "integrity": "sha512-mCOMec4BKd6BRGBZeSnGiIgwsbLGp3yhVqAD8H+PxiRNEHgDpZb8J1TnrSDlg97t0ySKMQJTHCWBCmBpSmkF6Q==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.56.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", + "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.5", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", + "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "dev": true + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "node_modules/@types/http-proxy": { + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.14.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", + "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + }, + "node_modules/@types/prop-types": { + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/react": { + "version": "18.3.3", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", + "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", + "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/retry": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.16.0.tgz", + "integrity": "sha512-py1miT6iQpJcs1BiJjm54AMzeuMPBSPuKPlnT8HlfudbcS5rYeX5jajpLf3mrdRh9dA/Ec2FVUY0ifeVNDIhZw==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/type-utils": "7.16.0", + "@typescript-eslint/utils": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.16.0.tgz", + "integrity": "sha512-j0fuUswUjDHfqV/UdW6mLtOQQseORqfdmoBNDFOqs9rvNVR2e+cmu6zJu/Ku4SDuqiJko6YnhwcL8x45r8Oqxg==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "7.16.0", + "@typescript-eslint/utils": "7.16.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.0.tgz", + "integrity": "sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/typescript-estree": "7.16.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.16.0.tgz", + "integrity": "sha512-ar9E+k7CU8rWi2e5ErzQiC93KKEFAXA2Kky0scAlPcxYblLt8+XZuHUZwlyfXILyQa95P6lQg+eZgh/dDs3+Vw==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/typescript-estree": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.16.0.tgz", + "integrity": "sha512-8gVv3kW6n01Q6TrI1cmTZ9YMFi3ucDT7i7aI5lEikk2ebk1AEjrwX8MDTdaX5D7fPXMBLvnsaa0IFTAu+jcfOw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.16.0.tgz", + "integrity": "sha512-fecuH15Y+TzlUutvUl9Cc2XJxqdLr7+93SQIbcZfd4XRGGKoxyljK27b+kxKamjRkU7FYC6RrbSCg0ALcZn/xw==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.16.0.tgz", + "integrity": "sha512-a5NTvk51ZndFuOLCh5OaJBELYc2O3Zqxfl3Js78VFE1zE46J2AaVuW+rEbVkQznjkmlzWsUI15BG5tQMixzZLw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.16.0.tgz", + "integrity": "sha512-rMo01uPy9C7XxG7AFsxa8zLnWXTF8N3PYclekWSrurvhwiw1eW88mrKiAYe6s53AUY57nTRz8dJsuuXdkAhzCg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.16.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.toreversed": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", + "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.9.1.tgz", + "integrity": "sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", + "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", + "dev": true, + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/babel-plugin-macros/node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dev": true, + "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.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bonjour-service": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", + "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001640", + "electron-to-chromium": "^1.4.820", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001642", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz", + "integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dev": true, + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/deep-equal": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.5", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.2", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-equal/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "dev": true, + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.827", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.827.tgz", + "integrity": "sha512-VY+J0e4SFcNfQy19MEoMdaIcZLmDCprqvBtkii1WTCTQHpRvf5N8+3kTYCgL/PcntvwQvmMJWTuDPsq+IlhWKQ==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", + "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/envinfo": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", + "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-get-iterator/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/es-iterator-helpers": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", + "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "dev": true + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.6.0.tgz", + "integrity": "sha512-ElQkdLMEEqQNM9Njff+2Y4q2afHk7JpkPvrd7Xh7xefwgQynqPxwf55J7di9+MEibWUGdNjFF9ITG9Pck5M84w==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/config-array": "^0.17.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.6.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.0.1", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "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" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-module-utils": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.9.0.tgz", + "integrity": "sha512-nOFOCaJG2pYqORjK19lqPqxMO/JpvdCZdPtNdxY3kvom3jTvkAbOvQvD8wuD0G8BYR0IGAGYDlzqWJOh/ybn2g==", + "dev": true, + "dependencies": { + "aria-query": "~5.1.3", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.9.1", + "axobject-query": "~3.1.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "es-iterator-helpers": "^1.0.19", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.0" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "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 + } + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.34.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.3.tgz", + "integrity": "sha512-aoW4MV891jkUulwDApQbPYTVZmeuSyFrudpbTAQuj5Fv8VL+o6df2xIGpw8B0hPjAaih1/Fb0om9grCdyFYemA==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.toreversed": "^1.1.2", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.19", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.8", + "object.fromentries": "^2.0.8", + "object.hasown": "^1.1.4", + "object.values": "^1.2.0", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.11" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", + "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-react/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.1.tgz", + "integrity": "sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "dev": true, + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.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" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "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" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/foreground-child": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", + "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-9.0.2.tgz", + "integrity": "sha512-Uochze2R8peoN1XqlSi/rGUkDQpRogtLFocP9+PGu68zk1BDAKXfdeCdyVZpgTk8V8WFVQXdEz426VKjXLO1Gg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cosmiconfig": "^8.2.0", + "deepmerge": "^4.2.2", + "fs-extra": "^10.0.0", + "memfs": "^3.4.1", + "minimatch": "^3.0.4", + "node-abort-controller": "^3.0.1", + "schema-utils": "^3.1.1", + "semver": "^7.3.5", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">=12.13.0", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "typescript": ">3.6.0", + "webpack": "^5.11.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globals": { + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.8.0.tgz", + "integrity": "sha512-VZAJ4cewHTExBWDHR6yptdIBlx9YSSZuwojj9Nt5mBRXQzrKakDsVKQ1J63sklLvzAJm0X5+RpO4i3Y2hcOnFw==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-5.0.0.tgz", + "integrity": "sha512-puaGKdjdVVIFRtgIC2n5dt5bt0N5j6heXlAQZ4Do1MLjHmOT1gCE1Ogg7XZNeJlnOVHHsrZKGs5dfh+XwZ3XPw==", + "dev": true, + "dependencies": { + "html-minifier-terser": "^7.2.0", + "parse5": "^7.1.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/html-loader/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/html-loader/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/html-loader/node_modules/html-minifier-terser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", + "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "~5.3.2", + "commander": "^10.0.0", + "entities": "^4.4.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.15.1" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + } + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", + "integrity": "sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==", + "dev": true, + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "dev": true, + "engines": { + "node": ">=10.18" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", + "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-network-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", + "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dev": true, + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/iterator.prototype": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "dev": true + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/launch-editor": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.0.tgz", + "integrity": "sha512-vJranOAJrI/llyWGRQqiDM+adrw+k83fvmmx3+nV47g3+36xM15jE+zyZ6Ffel02+xSvuM0b2GDRosXZkbb6wA==", + "dev": true, + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.9.3.tgz", + "integrity": "sha512-bsYSSnirtYTWi1+OPMFb0M048evMKyUYe0EbtuGQgq6BVQM1g1W8/KIUJCCvjgI/El0j6Q4WsmMiBwLUBSw8LA==", + "dev": true, + "dependencies": { + "@jsonjoy.com/json-pack": "^1.0.3", + "@jsonjoy.com/util": "^1.1.2", + "tree-dump": "^1.0.1", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">= 4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "dev": true + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.hasown": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", + "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", + "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", + "dev": true, + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz", + "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "dev": true + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-router": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.24.1.tgz", + "integrity": "sha512-PTXFXGK2pyXpHzVo3rR9H7ip4lSPZZc0bHG5CARmj65fTT6qG7sTngmb6lcYu1gf3y/8KxORoy9yn59pGpCnpg==", + "dependencies": { + "@remix-run/router": "1.17.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.24.1.tgz", + "integrity": "sha512-U19KtXqooqw967Vw0Qcn5cOvrX5Ejo9ORmOtJMzYWtCT4/WOfFLIZGGsVLxcd9UkBO0mSTZtXqhZBsWlHr7+Sg==", + "dependencies": { + "@remix-run/router": "1.17.1", + "react-router": "6.24.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dev": true, + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", + "integrity": "sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": "14 >=14.20 || 16 >=16.20 || >=18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-applescript": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", + "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/spdy-transport/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/spdy-transport/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/spdy/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/spdy/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/string.prototype.includes": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.0.tgz", + "integrity": "sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/synckit": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", + "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.31.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.2.tgz", + "integrity": "sha512-LGyRZVFm/QElZHy/CPr/O4eNZOZIzsrQ92y4v9UJe/pFJjypje2yI3C2FmPtvUEnhadlSbmG2nXtdcjHOjCfxw==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/thingies": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", + "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", + "dev": true, + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "tslib": "^2" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tree-dump": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", + "integrity": "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==", + "dev": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-loader": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", + "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-loader/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.16.0.tgz", + "integrity": "sha512-kaVRivQjOzuoCXU6+hLnjo3/baxyzWVO5GrnExkFzETRYJKVHYkrJglOu2OCm8Hi9RPDWX1PTNNTpU5KRV0+RA==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "7.16.0", + "@typescript-eslint/parser": "7.16.0", + "@typescript-eslint/utils": "7.16.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.0.tgz", + "integrity": "sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/typescript-estree": "7.16.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/watchpack": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", + "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/webpack": { + "version": "5.93.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.93.0.tgz", + "integrity": "sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.7.1", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.2.1.tgz", + "integrity": "sha512-hRLz+jPQXo999Nx9fXVdKlg/aehsw1ajA9skAneGmT03xwmyuhvF93p6HUKKbWhXdcERtGTzUCtIQr+2IQegrA==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^4.6.0", + "mime-types": "^2.1.31", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.0.4.tgz", + "integrity": "sha512-dljXhUgx3HqKP2d8J/fUMvhxGhzjeNVarDLcbO/EWMSgRizDkxHQDZQaLFL5VJY9tRBj2Gz+rvCEYYvhbqPHNA==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.13", + "@types/connect-history-api-fallback": "^1.5.4", + "@types/express": "^4.17.21", + "@types/serve-index": "^1.9.4", + "@types/serve-static": "^1.15.5", + "@types/sockjs": "^0.3.36", + "@types/ws": "^8.5.10", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.2.1", + "chokidar": "^3.6.0", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.4.0", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.1.0", + "launch-editor": "^2.6.1", + "open": "^10.0.3", + "p-retry": "^6.2.0", + "rimraf": "^5.0.5", + "schema-utils": "^4.2.0", + "selfsigned": "^2.4.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^7.1.0", + "ws": "^8.16.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-server/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dev": true, + "dependencies": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } } diff --git a/client/package.json b/client/package.json index 7546cdc62..d9717163d 100644 --- a/client/package.json +++ b/client/package.json @@ -1,48 +1,50 @@ { - "name": "haengdong-client", - "version": "1.0.0", - "description": "", - "type": "module", - "scripts": { - "start": "webpack serve ", - "build": "webpack --mode production", - "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'", - "format": "prettier --write 'src/**/*.{js,jsx,ts,tsx,json,css,scss,md}'" - }, - "keywords": [], - "author": "", - "license": "ISC", - "devDependencies": { - "@eslint/compat": "^1.1.0", - "@eslint/js": "^9.6.0", - "@types/react": "^18.3.3", - "@types/react-dom": "^18.3.0", - "@typescript-eslint/eslint-plugin": "^7.16.0", - "@typescript-eslint/parser": "^7.16.0", - "eslint": "^9.6.0", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jsx-a11y": "^6.9.0", - "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-react": "^7.34.3", - "eslint-plugin-react-hooks": "^4.6.2", - "fork-ts-checker-webpack-plugin": "^9.0.2", - "globals": "^15.8.0", - "html-loader": "^5.0.0", - "html-webpack-plugin": "^5.6.0", - "prettier": "3.3.2", - "ts-loader": "^9.5.1", - "typescript": "^5.5.3", - "typescript-eslint": "^7.16.0", - "webpack-cli": "^5.1.4", - "webpack-dev-server": "^5.0.4" - }, - "dependencies": { - "react": "^18.3.1", - "react-dom": "^18.3.1", - "react-router-dom": "^6.24.1" - }, - "engines": { - "npm": ">=10.7.0", - "node": ">=20.15.1" - } -} \ No newline at end of file + "name": "haengdong-client", + "version": "1.0.0", + "description": "", + "type": "module", + "scripts": { + "start": "webpack serve ", + "build": "webpack --mode production", + "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'", + "format": "prettier --write 'src/**/*.{js,jsx,ts,tsx,json,css,scss,md}'" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@eslint/compat": "^1.1.0", + "@eslint/js": "^9.6.0", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^7.16.0", + "@typescript-eslint/parser": "^7.16.0", + "eslint": "^9.6.0", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-jsx-a11y": "^6.9.0", + "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-react": "^7.34.3", + "eslint-plugin-react-hooks": "^4.6.2", + "fork-ts-checker-webpack-plugin": "^9.0.2", + "globals": "^15.8.0", + "html-loader": "^5.0.0", + "html-webpack-plugin": "^5.6.0", + "prettier": "3.3.2", + "ts-loader": "^9.5.1", + "typescript": "^5.5.3", + "typescript-eslint": "^7.16.0", + "webpack": "^5.93.0", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^5.0.4" + }, + "dependencies": { + "@emotion/react": "^11.11.4", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.24.1" + }, + "engines": { + "npm": ">=10.7.0", + "node": ">=20.15.1" + } +} From 32f623ab3351ae2d2365f7750674da74441fa0ea Mon Sep 17 00:00:00 2001 From: pakxe Date: Mon, 15 Jul 2024 20:38:18 +0900 Subject: [PATCH 008/178] =?UTF-8?q?chore:=20css=20props=EB=A5=BC=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=98=EA=B8=B0=20=EC=9C=84=ED=95=B4=20'js?= =?UTF-8?q?xImportSource'=20=EC=98=B5=EC=85=98=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari --- client/tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/client/tsconfig.json b/client/tsconfig.json index c3bf098d3..6ecb17ef8 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -31,6 +31,7 @@ "alwaysStrict": true, "noImplicitReturns": true, "forceConsistentCasingInFileNames": true, + "jsxImportSource": "@emotion/react", "baseUrl": "./", "paths": { From a8515a59b83f2987cfc41dba766ec963a68b6e5d Mon Sep 17 00:00:00 2001 From: pakxe Date: Mon, 15 Jul 2024 20:39:13 +0900 Subject: [PATCH 009/178] =?UTF-8?q?chore:=20css=20props=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=20=EC=9C=84=ED=95=B4=20=EB=AA=A8=EB=93=A0=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=B5=9C=EC=83=81=EB=8B=A8=EC=97=90=20=EC=A3=BC?= =?UTF-8?q?=EC=84=9D=EC=9D=84=20=EC=9E=90=EB=8F=99=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=ED=95=B4=EC=A3=BC=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=ED=94=8C=EB=9F=AC=EA=B7=B8=EC=9D=B8=20=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari --- client/webpack.config.js | 73 ++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/client/webpack.config.js b/client/webpack.config.js index 03798e534..9dd8ce0fb 100644 --- a/client/webpack.config.js +++ b/client/webpack.config.js @@ -1,38 +1,47 @@ -import path from "path"; -import HtmlWebpackPlugin from "html-webpack-plugin"; -import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin"; -import { fileURLToPath } from "url"; +import path from 'path'; +import HtmlWebpackPlugin from 'html-webpack-plugin'; +import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; +import {ModifySourcePlugin, ConcatOperation} from 'modify-source-webpack-plugin'; +import {fileURLToPath} from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); export default { - mode: "development", - entry: "./src/index.tsx", - resolve: { - extensions: [".js", ".jsx", ".ts", ".tsx"], - }, - output: { - path: path.join(__dirname, "dist"), - filename: "bundle.min.js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - loader: "ts-loader", - exclude: /node_modules/, - }, - ], - }, - plugins: [ - new HtmlWebpackPlugin({ - template: "./index.html", - }), - new ForkTsCheckerWebpackPlugin(), - ], - devServer: { - port: 3000, - hot: true, - }, + mode: 'development', + entry: './src/index.tsx', + resolve: { + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }, + output: { + path: path.join(__dirname, 'dist'), + filename: 'bundle.min.js', + }, + module: { + rules: [ + { + test: /\.tsx?$/, + loader: 'ts-loader', + exclude: /node_modules/, + }, + ], + }, + plugins: [ + new HtmlWebpackPlugin({ + template: './index.html', + }), + new ForkTsCheckerWebpackPlugin(), + new ModifySourcePlugin({ + rules: [ + { + test: /\.tsx$/i, + operations: [new ConcatOperation('start', '/** @jsxImportSource @emotion/react */\n\n')], + }, + ], + }), + ], + devServer: { + port: 3001, + hot: true, + }, }; From 80c352f660c2f4ae6ef04bef6908184e40758f41 Mon Sep 17 00:00:00 2001 From: pakxe Date: Mon, 15 Jul 2024 20:42:55 +0900 Subject: [PATCH 010/178] =?UTF-8?q?chore:=20=EA=B0=9C=EB=B0=9C=EC=84=9C?= =?UTF-8?q?=EB=B2=84=20=ED=8F=AC=ED=8A=B8=EB=B2=88=ED=98=B8=203001=20->=20?= =?UTF-8?q?3000=20=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari --- client/webpack.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/webpack.config.js b/client/webpack.config.js index 9dd8ce0fb..9f355cf8f 100644 --- a/client/webpack.config.js +++ b/client/webpack.config.js @@ -41,7 +41,7 @@ export default { }), ], devServer: { - port: 3001, + port: 3000, hot: true, }, }; From c7cae03bb984636a7c205b65a9b082cbc9896415 Mon Sep 17 00:00:00 2001 From: pakxe Date: Mon, 15 Jul 2024 20:43:21 +0900 Subject: [PATCH 011/178] =?UTF-8?q?chore:=20prettier=EC=97=90=EC=84=9C=20u?= =?UTF-8?q?seTabs=EB=A5=BC=20=EC=82=AC=EC=9A=A9=ED=95=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EB=8F=84=EB=A1=9D=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari --- client/.prettierrc | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/client/.prettierrc b/client/.prettierrc index fce76bb96..a661f29c2 100644 --- a/client/.prettierrc +++ b/client/.prettierrc @@ -1,13 +1,12 @@ { - "singleQuote": true, - "trailingComma": "all", - "printWidth": 120, - "tabWidth": 2, - "semi": true, - "arrowParens": "avoid", - "endOfLine": "auto", - "jsxSingleQuote": false, - "bracketSpacing": false, - "proseWrap": "preserve", - "useTabs": true -} \ No newline at end of file + "singleQuote": true, + "trailingComma": "all", + "printWidth": 120, + "tabWidth": 2, + "semi": true, + "arrowParens": "avoid", + "endOfLine": "auto", + "jsxSingleQuote": false, + "bracketSpacing": false, + "proseWrap": "preserve" +} From 288718bf0be19924442dcf22069b542ef0d18444 Mon Sep 17 00:00:00 2001 From: pakxe Date: Mon, 15 Jul 2024 21:03:29 +0900 Subject: [PATCH 012/178] =?UTF-8?q?chore:=20=EC=97=AC=EB=9F=AC=20=EB=AA=85?= =?UTF-8?q?=EC=9D=B4=20co-authored-by=EB=A1=9C=20=EB=93=A4=EC=96=B4?= =?UTF-8?q?=EA=B0=88=20=EC=88=98=20=EC=9E=88=EB=8A=94=EC=A7=80=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe Co-authored-by: soi-ha Co-authored-by: jinhokim98 Co-authored-by: Todari Co-authored-by: pakxe Co-authored-by: soi-ha Co-authored-by: jinhokim98 Co-authored-by: Todari --- client/src/App.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/src/App.tsx b/client/src/App.tsx index b5b756a36..5a7e5f458 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,12 +1,13 @@ import {css} from '@emotion/react'; +// co-authored-by test // 테스트 css props 사용 예제입니다. 추후 삭제 예정 const style = css` - color: red; + color: red; `; const App: React.FC = () => { - return
Hello, React with Webpack
; + return
Hello, React with Webpack
; }; export default App; From 5fe7696d529f42c0cffe75ab7afd85e1c6de88be Mon Sep 17 00:00:00 2001 From: pakxe Date: Mon, 15 Jul 2024 21:04:18 +0900 Subject: [PATCH 013/178] =?UTF-8?q?chore:=20=EC=9E=84=EC=8B=9C=EB=A1=9C=20?= =?UTF-8?q?=EC=A7=80=EC=9B=A0=EB=8D=98=20types=20=EC=98=B5=EC=85=98?= =?UTF-8?q?=EC=9D=84=20=EB=8B=A4=EC=8B=9C=20=ED=99=9C=EC=84=B1=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe Co-authored-by: soi-ha Co-authored-by: jinhokim98 Co-authored-by: Todari Co-authored-by: pakxe Co-authored-by: soi-ha Co-authored-by: jinhokim98 Co-authored-by: Todari --- client/tsconfig.json | 74 ++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/client/tsconfig.json b/client/tsconfig.json index 6ecb17ef8..be12e5cfb 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -1,43 +1,43 @@ { - "compilerOptions": { - "sourceMap": true, - "module": "ES2020", - "target": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "useDefineForClassFields": true, - "removeComments": true, - "skipLibCheck": true, + "compilerOptions": { + "sourceMap": true, + "module": "ES2020", + "target": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "useDefineForClassFields": true, + "removeComments": true, + "skipLibCheck": true, - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, - "jsx": "react-jsx", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, - "types": ["jest"], - "esModuleInterop": true, - "strictNullChecks": true, - "strictFunctionTypes": true, - "strictBindCallApply": true, - "strictPropertyInitialization": true, - "noImplicitAny": true, - "noImplicitThis": true, - "alwaysStrict": true, - "noImplicitReturns": true, - "forceConsistentCasingInFileNames": true, - "jsxImportSource": "@emotion/react", + "types": ["jest"], + "esModuleInterop": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictBindCallApply": true, + "strictPropertyInitialization": true, + "noImplicitAny": true, + "noImplicitThis": true, + "alwaysStrict": true, + "noImplicitReturns": true, + "forceConsistentCasingInFileNames": true, + "jsxImportSource": "@emotion/react", - "baseUrl": "./", - "paths": { - "components/*": ["src/components/*"] - }, - "outDir": "./dist" - }, - "include": ["src"] + "baseUrl": "./", + "paths": { + "components/*": ["src/components/*"] + }, + "outDir": "./dist" + }, + "include": ["src"] } From 748656c951bbc8162343f6aa9707bded3f186ab0 Mon Sep 17 00:00:00 2001 From: Soyeon Choe Date: Mon, 15 Jul 2024 22:41:03 +0900 Subject: [PATCH 014/178] =?UTF-8?q?chore:=20=EA=B8=B0=EB=B3=B8=20webpack?= =?UTF-8?q?=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> --- HDesign/.gitignore | 11 + HDesign/.npmrc | 2 + HDesign/.prettierrc | 12 + HDesign/.storybook/main.ts | 18 + HDesign/.storybook/preview.ts | 14 + HDesign/eslint.config.mjs | 127 + HDesign/package-lock.json | 15532 ++++++++++++++++++++++++++++++++ HDesign/package.json | 66 + HDesign/tsconfig.json | 43 + HDesign/webpack.config.js | 48 + 10 files changed, 15873 insertions(+) create mode 100644 HDesign/.gitignore create mode 100644 HDesign/.npmrc create mode 100644 HDesign/.prettierrc create mode 100644 HDesign/.storybook/main.ts create mode 100644 HDesign/.storybook/preview.ts create mode 100644 HDesign/eslint.config.mjs create mode 100644 HDesign/package-lock.json create mode 100644 HDesign/package.json create mode 100644 HDesign/tsconfig.json create mode 100644 HDesign/webpack.config.js diff --git a/HDesign/.gitignore b/HDesign/.gitignore new file mode 100644 index 000000000..afd0485d1 --- /dev/null +++ b/HDesign/.gitignore @@ -0,0 +1,11 @@ +logs +*.log +npm-debug.log* + +node_modules +dist + +.env + +*storybook.log +.DS_Store diff --git a/HDesign/.npmrc b/HDesign/.npmrc new file mode 100644 index 000000000..ece05f588 --- /dev/null +++ b/HDesign/.npmrc @@ -0,0 +1,2 @@ +engine-strict = true +legacy-peer-deps = true diff --git a/HDesign/.prettierrc b/HDesign/.prettierrc new file mode 100644 index 000000000..c025201f4 --- /dev/null +++ b/HDesign/.prettierrc @@ -0,0 +1,12 @@ +{ + "singleQuote": true, + "trailingComma": "all", + "printWidth": 120, + "tabWidth": 2, + "semi": true, + "arrowParens": "avoid", + "endOfLine": "auto", + "jsxSingleQuote": false, + "bracketSpacing": false, + "proseWrap": "preserve" +} diff --git a/HDesign/.storybook/main.ts b/HDesign/.storybook/main.ts new file mode 100644 index 000000000..dcdd7bf09 --- /dev/null +++ b/HDesign/.storybook/main.ts @@ -0,0 +1,18 @@ +import type {StorybookConfig} from '@storybook/react-webpack5'; + +const config: StorybookConfig = { + stories: ['../stories/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'], + addons: [ + '@storybook/addon-webpack5-compiler-swc', + '@storybook/addon-onboarding', + '@storybook/addon-links', + '@storybook/addon-essentials', + '@chromatic-com/storybook', + '@storybook/addon-interactions', + ], + framework: { + name: '@storybook/react-webpack5', + options: {}, + }, +}; +export default config; diff --git a/HDesign/.storybook/preview.ts b/HDesign/.storybook/preview.ts new file mode 100644 index 000000000..a66ea2ee6 --- /dev/null +++ b/HDesign/.storybook/preview.ts @@ -0,0 +1,14 @@ +import type {Preview} from '@storybook/react'; + +const preview: Preview = { + parameters: { + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/i, + }, + }, + }, +}; + +export default preview; diff --git a/HDesign/eslint.config.mjs b/HDesign/eslint.config.mjs new file mode 100644 index 000000000..ea53f995c --- /dev/null +++ b/HDesign/eslint.config.mjs @@ -0,0 +1,127 @@ +import path from 'node:path'; +import {fileURLToPath} from 'node:url'; + +import {fixupConfigRules, fixupPluginRules} from '@eslint/compat'; +import react from 'eslint-plugin-react'; +import typescriptEslint from '@typescript-eslint/eslint-plugin'; +import _import from 'eslint-plugin-import'; +import prettier from 'eslint-plugin-prettier'; +import tsParser from '@typescript-eslint/parser'; +import js from '@eslint/js'; +import {FlatCompat} from '@eslint/eslintrc'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + allConfig: js.configs.all, +}); + +export default [ + ...fixupConfigRules( + compat.extends( + 'airbnb', + 'airbnb/hooks', + 'eslint:recommended', + 'plugin:react/recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:react-hooks/recommended', + 'plugin:import/typescript', + 'plugin:import/recommended', + 'plugin:import/errors', + 'plugin:import/warnings', + 'prettier', + 'plugin:prettier/recommended', + ), + ), + { + plugins: { + react: fixupPluginRules(react), + '@typescript-eslint': fixupPluginRules(typescriptEslint), + import: fixupPluginRules(_import), + prettier: fixupPluginRules(prettier), + }, + + languageOptions: { + parser: tsParser, + }, + + settings: { + 'import/resolver': { + node: { + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }, + + typescript: { + directory: './lib', + }, + }, + + 'import/parsers': { + '@typescript-eslint/parser': ['.ts', '.tsx'], + }, + }, + + rules: { + 'prettier/prettier': 'error', + 'react/react-in-jsx-scope': 'off', + 'react/prop-types': 'off', + 'react/jsx-uses-vars': 'error', + '@typescript-eslint/no-use-before-define': ['error'], + '@typescript-eslint/explicit-module-boundary-types': 'error', + + 'import/order': [ + 'error', + { + 'newlines-between': 'always', + + groups: ['type', 'builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'unknown'], + + pathGroups: [ + { + pattern: 'react*', + group: 'external', + position: 'before', + }, + { + pattern: '@hooks/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@apis/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@pages/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@components/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@assets/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@utils/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@constants/*', + group: 'internal', + position: 'after', + }, + ], + }, + ], + }, + }, +]; diff --git a/HDesign/package-lock.json b/HDesign/package-lock.json new file mode 100644 index 000000000..0d86a87a3 --- /dev/null +++ b/HDesign/package-lock.json @@ -0,0 +1,15532 @@ +{ + "name": "haengdong-design", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "haengdong-design", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@emotion/react": "^11.11.4", + "modify-source-webpack-plugin": "^4.1.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.24.1" + }, + "devDependencies": { + "@chromatic-com/storybook": "^1.6.1", + "@eslint/compat": "^1.1.0", + "@eslint/js": "^9.6.0", + "@storybook/addon-essentials": "^8.2.2", + "@storybook/addon-interactions": "^8.2.2", + "@storybook/addon-links": "^8.2.2", + "@storybook/addon-onboarding": "^8.2.2", + "@storybook/addon-webpack5-compiler-swc": "^1.0.4", + "@storybook/blocks": "^8.2.2", + "@storybook/react": "^8.2.2", + "@storybook/react-webpack5": "^8.2.2", + "@storybook/test": "^8.2.2", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^7.16.0", + "@typescript-eslint/parser": "^7.16.0", + "eslint": "^8.57.0", + "eslint-config-airbnb": "^19.0.4", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-jsx-a11y": "^6.9.0", + "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-react": "^7.34.4", + "eslint-plugin-react-hooks": "^4.6.2", + "eslint-plugin-storybook": "^0.8.0", + "fork-ts-checker-webpack-plugin": "^9.0.2", + "globals": "^15.8.0", + "html-loader": "^5.0.0", + "html-webpack-plugin": "^5.6.0", + "prettier": "3.3.2", + "storybook": "^8.2.2", + "ts-loader": "^9.5.1", + "typescript": "^5.5.3", + "typescript-eslint": "^7.16.0", + "webpack": "^5.93.0", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^5.0.4" + }, + "engines": { + "node": ">=20.15.1", + "npm": ">=10.7.0" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.0.tgz", + "integrity": "sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==", + "dev": true + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.9.tgz", + "integrity": "sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz", + "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.9", + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-module-transforms": "^7.24.9", + "@babel/helpers": "^7.24.8", + "@babel/parser": "^7.24.8", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.9", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/@babel/core/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/core/node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/core/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.9.tgz", + "integrity": "sha512-G8v3jRg+z8IwY1jHFxvCNhOPYPterE4XljNgdGTYfSTtzzwjIswIzIaSPSLs3R7yFuqnqNeay5rjICfqVr+/6A==", + "dependencies": { + "@babel/types": "^7.24.9", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", + "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", + "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz", + "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.8.tgz", + "integrity": "sha512-4f6Oqnmyp2PP3olgUMmOwC3akxSm5aBYraQ6YDdKy7NcAMkDECHWG0DEnV6M2UAkERgIBhYt8S27rURPg7SxWA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.7.tgz", + "integrity": "sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", + "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", + "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", + "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", + "dependencies": { + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", + "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", + "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz", + "integrity": "sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", + "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.7.tgz", + "integrity": "sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-wrap-function": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz", + "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.7", + "@babel/helper-optimise-call-expression": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", + "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.7.tgz", + "integrity": "sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.24.7", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz", + "integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", + "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.7.tgz", + "integrity": "sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.7.tgz", + "integrity": "sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", + "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.7.tgz", + "integrity": "sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.24.7.tgz", + "integrity": "sha512-9G8GYT/dxn/D1IIKOUBmGX0mnmj46mGH9NnZyJLwtCpgh5f7D2VbuKodb+2s9m1Yavh1s7ASQN8lf0eqrb1LTw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", + "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", + "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", + "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", + "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", + "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.7.tgz", + "integrity": "sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", + "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", + "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.7.tgz", + "integrity": "sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz", + "integrity": "sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", + "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.8.tgz", + "integrity": "sha512-VXy91c47uujj758ud9wx+OMgheXm4qJfyhj1P18YvlrQkNOSrwsteHk+EFS3OMGfhMhpZa0A+81eE7G4QC+3CA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-replace-supers": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", + "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/template": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", + "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", + "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", + "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", + "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", + "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", + "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.24.7.tgz", + "integrity": "sha512-cjRKJ7FobOH2eakx7Ja+KpJRj8+y+/SiB3ooYm/n2UJfxu0oEaOoxOinitkJcPqv9KxS0kxTGPUaR7L2XcXDXA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-flow": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", + "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.7.tgz", + "integrity": "sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", + "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.7.tgz", + "integrity": "sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", + "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", + "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", + "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", + "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-simple-access": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.7.tgz", + "integrity": "sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", + "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", + "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", + "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", + "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", + "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", + "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", + "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", + "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", + "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", + "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz", + "integrity": "sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", + "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", + "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", + "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", + "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", + "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", + "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", + "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", + "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", + "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.8.tgz", + "integrity": "sha512-CgFgtN61BbdOGCP4fLaAMOPkzWUh6yQZNMr5YSt8uz2cZSSiQONCQFWqsE4NeVfOIhqDOlS9CR3WD91FzMeB2Q==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/plugin-syntax-typescript": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", + "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", + "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", + "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz", + "integrity": "sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.8.tgz", + "integrity": "sha512-vObvMZB6hNWuDxhSaEPTKCwcqkAIuDtE+bQGn4XMXne1DSLzFVY8Vmj1bm+mUQXYNN8NmaQEO+r8MMbzPr1jBQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.24.8", + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.24.7", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.24.7", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoped-functions": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.24.7", + "@babel/plugin-transform-class-properties": "^7.24.7", + "@babel/plugin-transform-class-static-block": "^7.24.7", + "@babel/plugin-transform-classes": "^7.24.8", + "@babel/plugin-transform-computed-properties": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-dotall-regex": "^7.24.7", + "@babel/plugin-transform-duplicate-keys": "^7.24.7", + "@babel/plugin-transform-dynamic-import": "^7.24.7", + "@babel/plugin-transform-exponentiation-operator": "^7.24.7", + "@babel/plugin-transform-export-namespace-from": "^7.24.7", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.24.7", + "@babel/plugin-transform-json-strings": "^7.24.7", + "@babel/plugin-transform-literals": "^7.24.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-member-expression-literals": "^7.24.7", + "@babel/plugin-transform-modules-amd": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-modules-systemjs": "^7.24.7", + "@babel/plugin-transform-modules-umd": "^7.24.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-new-target": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-numeric-separator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-object-super": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-property-literals": "^7.24.7", + "@babel/plugin-transform-regenerator": "^7.24.7", + "@babel/plugin-transform-reserved-words": "^7.24.7", + "@babel/plugin-transform-shorthand-properties": "^7.24.7", + "@babel/plugin-transform-spread": "^7.24.7", + "@babel/plugin-transform-sticky-regex": "^7.24.7", + "@babel/plugin-transform-template-literals": "^7.24.7", + "@babel/plugin-transform-typeof-symbol": "^7.24.8", + "@babel/plugin-transform-unicode-escapes": "^7.24.7", + "@babel/plugin-transform-unicode-property-regex": "^7.24.7", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.24.7", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.4", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.37.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-flow": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.24.7.tgz", + "integrity": "sha512-NL3Lo0NorCU607zU3NwRyJbpaB6E3t0xtd3LfAQKDfkeX4/ggcDXvkmkW42QWT5owUeW/jAe4hn+2qvkV1IbfQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "@babel/plugin-transform-flow-strip-types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.7.tgz", + "integrity": "sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "@babel/plugin-syntax-jsx": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.7", + "@babel/plugin-transform-typescript": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/register": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.24.6.tgz", + "integrity": "sha512-WSuFCc2wCqMeXkz/i3yfAAsxwWflEgbVkZzivgAmXl/MxrXeoYFZOOPllbC8R8WTF7u61wSRQtDVZ1879cdu6w==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "find-cache-dir": "^2.0.0", + "make-dir": "^2.1.0", + "pirates": "^4.0.6", + "source-map-support": "^0.5.16" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/register/node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/register/node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true + }, + "node_modules/@babel/runtime": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", + "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", + "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz", + "integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.8", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/parser": "^7.24.8", + "@babel/types": "^7.24.8", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/traverse/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@babel/types": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.9.tgz", + "integrity": "sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==", + "dependencies": { + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@base2/pretty-print-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz", + "integrity": "sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==", + "dev": true + }, + "node_modules/@chromatic-com/storybook": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@chromatic-com/storybook/-/storybook-1.6.1.tgz", + "integrity": "sha512-x1x1NB3j4xpfeSWKr96emc+7ZvfsvH+/WVb3XCjkB24PPbT8VZXb3mJSAQMrSzuQ8+eQE9kDogYHH9Fj3tb/Cw==", + "dev": true, + "dependencies": { + "chromatic": "^11.4.0", + "filesize": "^10.0.12", + "jsonfile": "^6.1.0", + "react-confetti": "^6.1.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=16.0.0", + "yarn": ">=1.22.18" + } + }, + "node_modules/@chromatic-com/storybook/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@chromatic-com/storybook/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", + "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/serialize": "^1.1.2", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "dependencies": { + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", + "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + }, + "node_modules/@emotion/react": { + "version": "11.11.4", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.4.tgz", + "integrity": "sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/cache": "^11.11.0", + "@emotion/serialize": "^1.1.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.4.tgz", + "integrity": "sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ==", + "dependencies": { + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/unitless": "^0.8.1", + "@emotion/utils": "^1.2.1", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" + }, + "node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", + "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/compat": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.1.0.tgz", + "integrity": "sha512-s9Wi/p25+KbzxKlDm3VshQdImhWk+cbdblhwGNnyCU5lpSwtWa4v7VQCxSki0FAUrGA3s8nCWgYzAH41mwQVKQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.7.0.tgz", + "integrity": "sha512-ChuWDQenef8OSFnvuxv0TCVxEwmu3+hPNKvM9B34qpM0rDRbjL8t5QkQeHHeAfsKQjuH9wS82WeCi1J/owatng==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", + "dev": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.0.4.tgz", + "integrity": "sha512-aOcSN4MeAtFROysrbqG137b7gaDDSmVrl5mpo6sT/w+kcXpWnzhMjmY/Fh/sDx26NBxyIE7MB1seqLeCAzy9Sg==", + "dev": true, + "dependencies": { + "@jsonjoy.com/base64": "^1.1.1", + "@jsonjoy.com/util": "^1.1.2", + "hyperdyperid": "^1.2.0", + "thingies": "^1.20.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.2.0.tgz", + "integrity": "sha512-4B8B+3vFsY4eo33DMKyJPlQ3sBMpPFUZK2dr3O3rXrOGKKbYG44J0XSFkDo1VOQiri5HFEhIeVvItjR2xcazmg==", + "dev": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true + }, + "node_modules/@mdx-js/react": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.0.1.tgz", + "integrity": "sha512-9ZrPIU4MGf6et1m1ov3zKf+q9+deetI51zprKB1D/z3NOb+rUxxtEl3mCjW5wTGh6VhRdwPueh1oRzi6ezkA8A==", + "dev": true, + "dependencies": { + "@types/mdx": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@remix-run/router": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.17.1.tgz", + "integrity": "sha512-mCOMec4BKd6BRGBZeSnGiIgwsbLGp3yhVqAD8H+PxiRNEHgDpZb8J1TnrSDlg97t0ySKMQJTHCWBCmBpSmkF6Q==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/addon-actions": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-8.2.2.tgz", + "integrity": "sha512-SN4cSRt3f0qXi5te+yhMseSdQuZntA8lGlASbRmN77YQTpIaGsNiH88xFoky0s9qz531hiRfU1R0ZSMylBwSKw==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0", + "@types/uuid": "^9.0.1", + "dequal": "^2.0.2", + "polished": "^4.2.2", + "uuid": "^9.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-actions/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@storybook/addon-backgrounds": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-8.2.2.tgz", + "integrity": "sha512-m/xJe7uKL+kfJx7pQcHwAeIvJ3tdLIpDGrMAVDNDJHcAxfe44cFjIInaV/1HKf3y5Awap+DZFW66ekkxuI9zzA==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0", + "memoizerific": "^1.11.3", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-controls": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-8.2.2.tgz", + "integrity": "sha512-y241aOANGzT5XBADUIvALwG/xF5eC6UItzmWJaFvOzSBCq74GIA0+Hu9atyFdvFQbXOrdvPWC4jR+9iuBFRxAA==", + "dev": true, + "dependencies": { + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-docs": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-8.2.2.tgz", + "integrity": "sha512-qk/yjAR9RpsSrKLLbeCgb6u58c8TmYqyJSnXgbAozZZNKHBWlIpvZ/hTNYud8qo0coPlxnLdjnZf32TykWGlAg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.24.4", + "@mdx-js/react": "^3.0.0", + "@storybook/blocks": "8.2.2", + "@storybook/csf-plugin": "8.2.2", + "@storybook/global": "^5.0.0", + "@storybook/react-dom-shim": "8.2.2", + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "fs-extra": "^11.1.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", + "rehype-external-links": "^3.0.0", + "rehype-slug": "^6.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-docs/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@storybook/addon-essentials": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-essentials/-/addon-essentials-8.2.2.tgz", + "integrity": "sha512-yN//BFMbSvNV0+Sll2hcKmgJX06TUKQDm6pZimUjkXczFtOmK7K/UdDmKjWS+qjhfJdWpxdRoEpxoHvvRmNfsA==", + "dev": true, + "dependencies": { + "@storybook/addon-actions": "8.2.2", + "@storybook/addon-backgrounds": "8.2.2", + "@storybook/addon-controls": "8.2.2", + "@storybook/addon-docs": "8.2.2", + "@storybook/addon-highlight": "8.2.2", + "@storybook/addon-measure": "8.2.2", + "@storybook/addon-outline": "8.2.2", + "@storybook/addon-toolbars": "8.2.2", + "@storybook/addon-viewport": "8.2.2", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-highlight": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-highlight/-/addon-highlight-8.2.2.tgz", + "integrity": "sha512-yDTRzzL+IJAymgY32xoZl09BGBVmPOUV2wVNGYcZkkBLvz2GSQMTfUe1/7F4jAx//+rFBu48/MQzsTC7Bk8kPw==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-interactions": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-interactions/-/addon-interactions-8.2.2.tgz", + "integrity": "sha512-zRRuUwm/l41JtTUgjIoQTUgLT99Hsdz9cqKca/8NYo1MGBdEcKE41DH4aBIzKaOKFu7p9q00/o/X1EqYX4LMUA==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0", + "@storybook/instrumenter": "8.2.2", + "@storybook/test": "8.2.2", + "polished": "^4.2.2", + "ts-dedent": "^2.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-links": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-8.2.2.tgz", + "integrity": "sha512-eGh7O7SgTJMtnuXC0HlRPOegu1njcJS2cnVqjbzjvjxsPSBhbHpdYMi9Q9E7al/FKuqMUOjIR9YLIlmK1AJaqA==", + "dev": true, + "dependencies": { + "@storybook/csf": "0.1.11", + "@storybook/global": "^5.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.2.2" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-measure": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-measure/-/addon-measure-8.2.2.tgz", + "integrity": "sha512-3rCo/aMltt5FrBVdr2dYlD8HlE2q9TLKGJZnwh9on4QyL6ArHbdYw0LmyHe/LrFahJ49w1XQZBMSJcAdRkkS7w==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0", + "tiny-invariant": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-onboarding": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-onboarding/-/addon-onboarding-8.2.2.tgz", + "integrity": "sha512-dCdE8Mt/JW6cq6dY7co35Sul/bAkUT3ixaxBrUagFUYUQ/PTYM6p4/B+45RURD5S9z8LVHH1rVgmEeScm3U78w==", + "dev": true, + "dependencies": { + "react-confetti": "^6.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-outline": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-outline/-/addon-outline-8.2.2.tgz", + "integrity": "sha512-Y+PQtfTNO8GLX5nz+3x5AMfHNvdGvBXazJ29+Rl1ygYN1+Q9ZhRJDE1kAK0wLxb7CG14peAgdYEaQb3Rduv7HQ==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-toolbars": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-toolbars/-/addon-toolbars-8.2.2.tgz", + "integrity": "sha512-JGOueOc3EPljlCl9dVSQee0aMYoqGNvN0UH+R6wYJ3bDZ+tUG/iYpsZVPUOvS8vzp3Imk5Is1kzQbQYJtzdGLg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-viewport": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-viewport/-/addon-viewport-8.2.2.tgz", + "integrity": "sha512-gkZ8bsjGGP0NuevkT2iKC+szezSy+w4BrBDknf490mRU2K/B2e7TGojf/j/AtxzILMzD4IKzKUXbE/zwcqjZvA==", + "dev": true, + "dependencies": { + "memoizerific": "^1.11.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-webpack5-compiler-swc": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@storybook/addon-webpack5-compiler-swc/-/addon-webpack5-compiler-swc-1.0.4.tgz", + "integrity": "sha512-S/ypdAK9oqwUAt3ZOn44qi3RWdH5uBLbBgtfHSXckqTpQRu7F7A9bRzjK+H5ti4xVADRhxu/xzIBwxWgcCeIXA==", + "dev": true, + "dependencies": { + "@swc/core": "1.5.7", + "swc-loader": "^0.2.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@storybook/blocks": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/blocks/-/blocks-8.2.2.tgz", + "integrity": "sha512-av0Tryg4toDl2L/d1ABErtsAk9wvM1su6+M4wq5/Go50sk5IjGTldhbZFa9zNOohxLkZwaj0Q5xAgJ1Y+m5KrQ==", + "dev": true, + "dependencies": { + "@storybook/csf": "0.1.11", + "@storybook/global": "^5.0.0", + "@storybook/icons": "^1.2.5", + "@types/lodash": "^4.14.167", + "color-convert": "^2.0.1", + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "markdown-to-jsx": "^7.4.5", + "memoizerific": "^1.11.3", + "polished": "^4.2.2", + "react-colorful": "^5.1.2", + "telejson": "^7.2.0", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.2.2" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/builder-webpack5": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/builder-webpack5/-/builder-webpack5-8.2.2.tgz", + "integrity": "sha512-ud6a3pRusbC/TvT1ed15INxSivyL2y2zI61O/MWQZmM8sZOIC6ObdHLtzU4+535IIqiXhPoQ/QiOBbejqjgZvw==", + "dev": true, + "dependencies": { + "@storybook/core-webpack": "8.2.2", + "@types/node": "^18.0.0", + "@types/semver": "^7.3.4", + "browser-assert": "^1.2.1", + "case-sensitive-paths-webpack-plugin": "^2.4.0", + "cjs-module-lexer": "^1.2.3", + "constants-browserify": "^1.0.0", + "css-loader": "^6.7.1", + "es-module-lexer": "^1.5.0", + "express": "^4.19.2", + "fork-ts-checker-webpack-plugin": "^8.0.0", + "fs-extra": "^11.1.0", + "html-webpack-plugin": "^5.5.0", + "magic-string": "^0.30.5", + "path-browserify": "^1.0.1", + "process": "^0.11.10", + "semver": "^7.3.7", + "style-loader": "^3.3.1", + "terser-webpack-plugin": "^5.3.1", + "ts-dedent": "^2.0.0", + "url": "^0.11.0", + "util": "^0.12.4", + "util-deprecate": "^1.0.2", + "webpack": "5", + "webpack-dev-middleware": "^6.1.2", + "webpack-hot-middleware": "^2.25.1", + "webpack-virtual-modules": "^0.6.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/fork-ts-checker-webpack-plugin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-8.0.0.tgz", + "integrity": "sha512-mX3qW3idpueT2klaQXBzrIM/pHw+T0B/V9KHEvNrqijTq9NFnMZU6oreVxDYcf33P8a5cW+67PjodNHthGnNVg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cosmiconfig": "^7.0.1", + "deepmerge": "^4.2.2", + "fs-extra": "^10.0.0", + "memfs": "^3.4.1", + "minimatch": "^3.0.4", + "node-abort-controller": "^3.0.1", + "schema-utils": "^3.1.1", + "semver": "^7.3.5", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">=12.13.0", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "typescript": ">3.6.0", + "webpack": "^5.11.0" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/@storybook/builder-webpack5/node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/webpack-dev-middleware": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.3.tgz", + "integrity": "sha512-A4ChP0Qj8oGociTs6UdlRUGANIGrCDL3y+pmQMc+dSsraXHCatFpmMey4mYELA+juqwUqwQsUgJJISXl1KWmiw==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.12", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/@storybook/codemod": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/codemod/-/codemod-8.2.2.tgz", + "integrity": "sha512-wRUVKLHVUhbLJYKW3QOufUxJGwaUT4jTCD8+HOGpHPdJO3NrwXu186xt4tuPZO2Y/NnacPeCQPsaK5ok4O8o7A==", + "dev": true, + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/preset-env": "^7.24.4", + "@babel/types": "^7.24.0", + "@storybook/core": "8.2.2", + "@storybook/csf": "0.1.11", + "@types/cross-spawn": "^6.0.2", + "cross-spawn": "^7.0.3", + "globby": "^14.0.1", + "jscodeshift": "^0.15.1", + "lodash": "^4.17.21", + "prettier": "^3.1.1", + "recast": "^0.23.5", + "tiny-invariant": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/codemod/node_modules/globby": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", + "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", + "dev": true, + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/codemod/node_modules/path-type": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/codemod/node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/core": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/core/-/core-8.2.2.tgz", + "integrity": "sha512-L4ojYI+Os/i5bCReDIlFgEDQSS94mbJlNU9WRzEGZpqNC5/hbFEC9Tip7P1MiRx9NrewkzU7b+UCP7mi3e4drQ==", + "dev": true, + "dependencies": { + "@storybook/csf": "0.1.11", + "@types/express": "^4.17.21", + "@types/node": "^18.0.0", + "browser-assert": "^1.2.1", + "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0", + "esbuild-register": "^3.5.0", + "express": "^4.19.2", + "process": "^0.11.10", + "recast": "^0.23.5", + "util": "^0.12.4", + "ws": "^8.2.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-webpack": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/core-webpack/-/core-webpack-8.2.2.tgz", + "integrity": "sha512-M5wzgNbotVXcfo7WkXIuDxcBl7tTjnQ27lmlSBk+cu63pDvNn4UMDan621FcvxWq2DbjgIj+PASZ4DzM5O+ovA==", + "dev": true, + "dependencies": { + "@types/node": "^18.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@storybook/core/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@storybook/csf": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.1.11.tgz", + "integrity": "sha512-dHYFQH3mA+EtnCkHXzicbLgsvzYjcDJ1JWsogbItZogkPHgSJM/Wr71uMkcvw8v9mmCyP4NpXJuu6bPoVsOnzg==", + "dev": true, + "dependencies": { + "type-fest": "^2.19.0" + } + }, + "node_modules/@storybook/csf-plugin": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-8.2.2.tgz", + "integrity": "sha512-3K2RUpDDvq3DT46qAIj2VBC+fzTTebRUcZUsRfS6G1AzaX9p25iClEHiwcJacFkgQKhkci8A/Ly3Z4JJ3b4Pgw==", + "dev": true, + "dependencies": { + "unplugin": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/global": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@storybook/global/-/global-5.0.0.tgz", + "integrity": "sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==", + "dev": true + }, + "node_modules/@storybook/icons": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@storybook/icons/-/icons-1.2.9.tgz", + "integrity": "sha512-cOmylsz25SYXaJL/gvTk/dl3pyk7yBFRfeXTsHvTA3dfhoU/LWSq0NKL9nM7WBasJyn6XPSGnLS4RtKXLw5EUg==", + "dev": true, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/instrumenter": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/instrumenter/-/instrumenter-8.2.2.tgz", + "integrity": "sha512-refwnHqKHhya45MgqakhMG0jKhTiEIAl0aOwAaQy9+zf9ncMIYQAXRQsSZ2Z188lFWE24wbeHKteb62a5ZfWwQ==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0", + "@vitest/utils": "^1.3.1", + "util": "^0.12.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/preset-react-webpack": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/preset-react-webpack/-/preset-react-webpack-8.2.2.tgz", + "integrity": "sha512-GJkDtw4Ac8icD66fotGXYE3rmZkIwASpNLOeGzyP4eMMNaf5vlvTDxwkY551cGbnA5P7r4UkGjDiWinB9XE4VQ==", + "dev": true, + "dependencies": { + "@storybook/core-webpack": "8.2.2", + "@storybook/react": "8.2.2", + "@storybook/react-docgen-typescript-plugin": "1.0.6--canary.9.0c3f3b7.0", + "@types/node": "^18.0.0", + "@types/semver": "^7.3.4", + "find-up": "^5.0.0", + "fs-extra": "^11.1.0", + "magic-string": "^0.30.5", + "react-docgen": "^7.0.0", + "resolve": "^1.22.8", + "semver": "^7.3.7", + "tsconfig-paths": "^4.2.0", + "webpack": "5" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.2.2" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/preset-react-webpack/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@storybook/preset-react-webpack/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/preset-react-webpack/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@storybook/preset-react-webpack/node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@storybook/preset-react-webpack/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/preset-react-webpack/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/preset-react-webpack/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/preset-react-webpack/node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@storybook/react": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-8.2.2.tgz", + "integrity": "sha512-U4p/RV78yhjEwEzem8U7wE5/3sSpnqreGsPdAHMCIHd69e9tVeF0rwrTJGp917RClPjBKgEcfelCuvOlby4MrA==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0", + "@storybook/react-dom-shim": "8.2.2", + "@types/escodegen": "^0.0.6", + "@types/estree": "^0.0.51", + "@types/node": "^18.0.0", + "acorn": "^7.4.1", + "acorn-jsx": "^5.3.1", + "acorn-walk": "^7.2.0", + "escodegen": "^2.1.0", + "html-tags": "^3.1.0", + "lodash": "^4.17.21", + "prop-types": "^15.7.2", + "react-element-to-jsx-string": "^15.0.0", + "semver": "^7.3.7", + "ts-dedent": "^2.0.0", + "type-fest": "~2.19", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.2.2", + "typescript": ">= 4.2.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/react-docgen-typescript-plugin": { + "version": "1.0.6--canary.9.0c3f3b7.0", + "resolved": "https://registry.npmjs.org/@storybook/react-docgen-typescript-plugin/-/react-docgen-typescript-plugin-1.0.6--canary.9.0c3f3b7.0.tgz", + "integrity": "sha512-KUqXC3oa9JuQ0kZJLBhVdS4lOneKTOopnNBK4tUAgoxWQ3u/IjzdueZjFr7gyBrXMoU6duutk3RQR9u8ZpYJ4Q==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "endent": "^2.0.1", + "find-cache-dir": "^3.3.1", + "flat-cache": "^3.0.4", + "micromatch": "^4.0.2", + "react-docgen-typescript": "^2.2.2", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "typescript": ">= 4.x", + "webpack": ">= 4" + } + }, + "node_modules/@storybook/react-docgen-typescript-plugin/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@storybook/react-docgen-typescript-plugin/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@storybook/react-dom-shim": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-8.2.2.tgz", + "integrity": "sha512-4fb1/yT9WXHzHjs0In6orIEZxga5eXd9UaXEFGudBgowCjDUVP9LabDdKTbGusz20lfaAkATsRG/W+EcSLoh8w==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/react-webpack5": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/react-webpack5/-/react-webpack5-8.2.2.tgz", + "integrity": "sha512-JPR2Lp88KbfRWgnAd4lKFRKuc9Up6YeqbaDb6sptOXXzDM4nOhlRXKqp2tIqyhfiKp3wmu3PksixqD8f8VS9CA==", + "dev": true, + "dependencies": { + "@storybook/builder-webpack5": "8.2.2", + "@storybook/preset-react-webpack": "8.2.2", + "@storybook/react": "8.2.2", + "@types/node": "^18.0.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.2.2", + "typescript": ">= 4.2.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/react-webpack5/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@storybook/react/node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "node_modules/@storybook/react/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@storybook/react/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/@storybook/test": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/test/-/test-8.2.2.tgz", + "integrity": "sha512-X2qAKErjTh1X7XLAZqCMtU0ZK8JuwdKmgiqU0oXWxIDmCX6/Dm9ZIcdMZHs/S+K/UnIByjNlQpTShLVfRUeN1w==", + "dev": true, + "dependencies": { + "@storybook/csf": "0.1.11", + "@storybook/instrumenter": "8.2.2", + "@testing-library/dom": "10.1.0", + "@testing-library/jest-dom": "6.4.5", + "@testing-library/user-event": "14.5.2", + "@vitest/expect": "1.6.0", + "@vitest/spy": "1.6.0", + "util": "^0.12.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@swc/core": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.5.7.tgz", + "integrity": "sha512-U4qJRBefIJNJDRCCiVtkfa/hpiZ7w0R6kASea+/KLp+vkus3zcLSB8Ub8SvKgTIxjWpwsKcZlPf5nrv4ls46SQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@swc/counter": "^0.1.2", + "@swc/types": "0.1.7" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.5.7", + "@swc/core-darwin-x64": "1.5.7", + "@swc/core-linux-arm-gnueabihf": "1.5.7", + "@swc/core-linux-arm64-gnu": "1.5.7", + "@swc/core-linux-arm64-musl": "1.5.7", + "@swc/core-linux-x64-gnu": "1.5.7", + "@swc/core-linux-x64-musl": "1.5.7", + "@swc/core-win32-arm64-msvc": "1.5.7", + "@swc/core-win32-ia32-msvc": "1.5.7", + "@swc/core-win32-x64-msvc": "1.5.7" + }, + "peerDependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.5.7.tgz", + "integrity": "sha512-bZLVHPTpH3h6yhwVl395k0Mtx8v6CGhq5r4KQdAoPbADU974Mauz1b6ViHAJ74O0IVE5vyy7tD3OpkQxL/vMDQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.5.7.tgz", + "integrity": "sha512-RpUyu2GsviwTc2qVajPL0l8nf2vKj5wzO3WkLSHAHEJbiUZk83NJrZd1RVbEknIMO7+Uyjh54hEh8R26jSByaw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.5.7.tgz", + "integrity": "sha512-cTZWTnCXLABOuvWiv6nQQM0hP6ZWEkzdgDvztgHI/+u/MvtzJBN5lBQ2lue/9sSFYLMqzqff5EHKlFtrJCA9dQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.5.7.tgz", + "integrity": "sha512-hoeTJFBiE/IJP30Be7djWF8Q5KVgkbDtjySmvYLg9P94bHg9TJPSQoC72tXx/oXOgXvElDe/GMybru0UxhKx4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.5.7.tgz", + "integrity": "sha512-+NDhK+IFTiVK1/o7EXdCeF2hEzCiaRSrb9zD7X2Z7inwWlxAntcSuzZW7Y6BRqGQH89KA91qYgwbnjgTQ22PiQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.5.7.tgz", + "integrity": "sha512-25GXpJmeFxKB+7pbY7YQLhWWjkYlR+kHz5I3j9WRl3Lp4v4UD67OGXwPe+DIcHqcouA1fhLhsgHJWtsaNOMBNg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.5.7.tgz", + "integrity": "sha512-0VN9Y5EAPBESmSPPsCJzplZHV26akC0sIgd3Hc/7S/1GkSMoeuVL+V9vt+F/cCuzr4VidzSkqftdP3qEIsXSpg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.5.7.tgz", + "integrity": "sha512-RtoNnstBwy5VloNCvmvYNApkTmuCe4sNcoYWpmY7C1+bPR+6SOo8im1G6/FpNem8AR5fcZCmXHWQ+EUmRWJyuA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.5.7.tgz", + "integrity": "sha512-Xm0TfvcmmspvQg1s4+USL3x8D+YPAfX2JHygvxAnCJ0EHun8cm2zvfNBcsTlnwYb0ybFWXXY129aq1wgFC9TpQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.5.7.tgz", + "integrity": "sha512-tp43WfJLCsKLQKBmjmY/0vv1slVywR5Q4qKjF5OIY8QijaEW7/8VwPyUyVoJZEnDgv9jKtUTG5PzqtIYPZGnyg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true + }, + "node_modules/@swc/types": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.7.tgz", + "integrity": "sha512-scHWahbHF0eyj3JsxG9CFJgFdFNaVQCNAimBlT6PzS3n/HptxqREjsm4OH6AN3lYcffZYSPxXW8ua2BEHp0lJQ==", + "dev": true, + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@testing-library/dom": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.1.0.tgz", + "integrity": "sha512-wdsYKy5zupPyLCW2Je5DLHSxSfbIp6h80WoHOQc+RPtmPGA52O9x5MJEkv92Sjonpq+poOAtUKhh1kBGAXBrNA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/dom/node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.4.5.tgz", + "integrity": "sha512-AguB9yvTXmCnySBP1lWjfNNUwpbElsaQ567lt2VdGqAdHtpieLgjmcVyv1q7PMIvLbgpDdkWV5Ydv3FEejyp2A==", + "dev": true, + "dependencies": { + "@adobe/css-tools": "^4.3.2", + "@babel/runtime": "^7.9.2", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "lodash": "^4.17.21", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + }, + "peerDependencies": { + "@jest/globals": ">= 28", + "@types/bun": "latest", + "@types/jest": ">= 28", + "jest": ">= 28", + "vitest": ">= 0.32" + }, + "peerDependenciesMeta": { + "@jest/globals": { + "optional": true + }, + "@types/bun": { + "optional": true + }, + "@types/jest": { + "optional": true + }, + "jest": { + "optional": true + }, + "vitest": { + "optional": true + } + } + }, + "node_modules/@testing-library/jest-dom/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true + }, + "node_modules/@testing-library/jest-dom/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/user-event": { + "version": "14.5.2", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.2.tgz", + "integrity": "sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==", + "dev": true, + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/@types/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-fXRhhUkG4H3TQk5dBhQ7m/JDdSNHKwR2BBia62lhwEIq9xGiQKLxd6LymNhn47SjXhsUEPmxi+PKw2OkW4LLjA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/doctrine": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/@types/doctrine/-/doctrine-0.0.9.tgz", + "integrity": "sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==", + "dev": true + }, + "node_modules/@types/emscripten": { + "version": "1.39.13", + "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.39.13.tgz", + "integrity": "sha512-cFq+fO/isvhvmuP/+Sl4K4jtU6E23DoivtbO4r50e3odaxAiVdbfSYRDdJ4gCdxx+3aRjhphS5ZMwIH4hFy/Cw==", + "dev": true + }, + "node_modules/@types/escodegen": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/escodegen/-/escodegen-0.0.6.tgz", + "integrity": "sha512-AjwI4MvWx3HAOaZqYsjKWyEObT9lcVV0Y0V8nXo6cXzN8ZiMxVhf6F3d/UNvXVGKrEzL/Dluc5p+y9GkzlTWig==", + "dev": true + }, + "node_modules/@types/eslint": { + "version": "8.56.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", + "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.5", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", + "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "dev": true + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "node_modules/@types/http-proxy": { + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/lodash": { + "version": "4.17.6", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.6.tgz", + "integrity": "sha512-OpXEVoCKSS3lQqjx9GGGOapBeuW5eUboYHRlHP9urXPX25IKZ6AnP5ZRxtVf63iieUbsHxLn8NQ5Nlftc6yzAA==", + "dev": true + }, + "node_modules/@types/mdx": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.14.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", + "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + }, + "node_modules/@types/prop-types": { + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/react": { + "version": "18.3.3", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", + "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", + "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/resolve": { + "version": "1.20.6", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz", + "integrity": "sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==", + "dev": true + }, + "node_modules/@types/retry": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==", + "dev": true + }, + "node_modules/@types/uuid": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", + "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", + "dev": true + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.16.0.tgz", + "integrity": "sha512-py1miT6iQpJcs1BiJjm54AMzeuMPBSPuKPlnT8HlfudbcS5rYeX5jajpLf3mrdRh9dA/Ec2FVUY0ifeVNDIhZw==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/type-utils": "7.16.0", + "@typescript-eslint/utils": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.16.0.tgz", + "integrity": "sha512-j0fuUswUjDHfqV/UdW6mLtOQQseORqfdmoBNDFOqs9rvNVR2e+cmu6zJu/Ku4SDuqiJko6YnhwcL8x45r8Oqxg==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "7.16.0", + "@typescript-eslint/utils": "7.16.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.0.tgz", + "integrity": "sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/typescript-estree": "7.16.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.16.0.tgz", + "integrity": "sha512-ar9E+k7CU8rWi2e5ErzQiC93KKEFAXA2Kky0scAlPcxYblLt8+XZuHUZwlyfXILyQa95P6lQg+eZgh/dDs3+Vw==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/typescript-estree": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.16.0.tgz", + "integrity": "sha512-8gVv3kW6n01Q6TrI1cmTZ9YMFi3ucDT7i7aI5lEikk2ebk1AEjrwX8MDTdaX5D7fPXMBLvnsaa0IFTAu+jcfOw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.16.0.tgz", + "integrity": "sha512-fecuH15Y+TzlUutvUl9Cc2XJxqdLr7+93SQIbcZfd4XRGGKoxyljK27b+kxKamjRkU7FYC6RrbSCg0ALcZn/xw==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.16.0.tgz", + "integrity": "sha512-a5NTvk51ZndFuOLCh5OaJBELYc2O3Zqxfl3Js78VFE1zE46J2AaVuW+rEbVkQznjkmlzWsUI15BG5tQMixzZLw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": 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.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.16.0.tgz", + "integrity": "sha512-rMo01uPy9C7XxG7AFsxa8zLnWXTF8N3PYclekWSrurvhwiw1eW88mrKiAYe6s53AUY57nTRz8dJsuuXdkAhzCg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.16.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/@vitest/expect": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", + "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", + "dev": true, + "dependencies": { + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", + "chai": "^4.3.10" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", + "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", + "dev": true, + "dependencies": { + "tinyspy": "^2.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", + "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", + "dev": true, + "dependencies": { + "diff-sequences": "^29.6.3", + "estree-walker": "^3.0.3", + "loupe": "^2.3.7", + "pretty-format": "^29.7.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@vitest/utils/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@vitest/utils/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/@yarnpkg/fslib": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@yarnpkg/fslib/-/fslib-2.10.3.tgz", + "integrity": "sha512-41H+Ga78xT9sHvWLlFOZLIhtU6mTGZ20pZ29EiZa97vnxdohJD2AF42rCoAoWfqUz486xY6fhjMH+DYEM9r14A==", + "dev": true, + "dependencies": { + "@yarnpkg/libzip": "^2.3.0", + "tslib": "^1.13.0" + }, + "engines": { + "node": ">=12 <14 || 14.2 - 14.9 || >14.10.0" + } + }, + "node_modules/@yarnpkg/fslib/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/@yarnpkg/libzip": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/libzip/-/libzip-2.3.0.tgz", + "integrity": "sha512-6xm38yGVIa6mKm/DUCF2zFFJhERh/QWp1ufm4cNUvxsONBmfPg8uZ9pZBdOmF6qFGr/HlT6ABBkCSx/dlEtvWg==", + "dev": true, + "dependencies": { + "@types/emscripten": "^1.39.6", + "tslib": "^1.13.0" + }, + "engines": { + "node": ">=12 <14 || 14.2 - 14.9 || >14.10.0" + } + }, + "node_modules/@yarnpkg/libzip/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.toreversed": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", + "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.9.1.tgz", + "integrity": "sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", + "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", + "dev": true, + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/babel-core": { + "version": "7.0.0-bridge.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", + "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", + "dev": true, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/babel-plugin-macros/node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", + "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.2", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz", + "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.1", + "core-js-compat": "^3.36.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", + "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dev": true, + "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.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bonjour-service": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-assert": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/browser-assert/-/browser-assert-1.2.1.tgz", + "integrity": "sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ==", + "dev": true + }, + "node_modules/browserslist": { + "version": "4.23.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", + "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001640", + "electron-to-chromium": "^1.4.820", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001642", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz", + "integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/case-sensitive-paths-webpack-plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", + "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/chai": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", + "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chromatic": { + "version": "11.5.5", + "resolved": "https://registry.npmjs.org/chromatic/-/chromatic-11.5.5.tgz", + "integrity": "sha512-YS0GJwegF0vpMbwZE68/xJlI4SlUGMqI78V2ATAF19YwTHaq8jGP1CPQGKUSlgWUhzPtyu3ELy6Dvv/owYljAg==", + "dev": true, + "bin": { + "chroma": "dist/bin.js", + "chromatic": "dist/bin.js", + "chromatic-cli": "dist/bin.js" + }, + "peerDependencies": { + "@chromatic-com/cypress": "^0.*.* || ^1.0.0", + "@chromatic-com/playwright": "^0.*.* || ^1.0.0" + }, + "peerDependenciesMeta": { + "@chromatic-com/cypress": { + "optional": true + }, + "@chromatic-com/playwright": { + "optional": true + } + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "dev": true, + "dependencies": { + "consola": "^3.2.3" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz", + "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==", + "dev": true + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dev": true, + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/confbox": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz", + "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==", + "dev": true + }, + "node_modules/confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", + "dev": true + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/consola": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", + "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==", + "dev": true, + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/core-js-compat": { + "version": "3.37.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", + "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "dev": true, + "dependencies": { + "type-fest": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/css-loader": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", + "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true + }, + "node_modules/deep-eql": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-equal": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.5", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.2", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-equal/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "dev": true, + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "dev": true + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.827", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.827.tgz", + "integrity": "sha512-VY+J0e4SFcNfQy19MEoMdaIcZLmDCprqvBtkii1WTCTQHpRvf5N8+3kTYCgL/PcntvwQvmMJWTuDPsq+IlhWKQ==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/endent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/endent/-/endent-2.1.0.tgz", + "integrity": "sha512-r8VyPX7XL8U01Xgnb1CjZ3XV+z90cXIJ9JPE/R9SEC9vpw2P6CfsRPJmp20DppC5N7ZAMCmjYkJIa744Iyg96w==", + "dev": true, + "dependencies": { + "dedent": "^0.7.0", + "fast-json-parse": "^1.0.3", + "objectorarray": "^1.0.5" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", + "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/envinfo": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", + "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-get-iterator/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/es-iterator-helpers": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", + "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "dev": true + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/esbuild-register": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.5.0.tgz", + "integrity": "sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "esbuild": ">=0.12 <1" + } + }, + "node_modules/esbuild-register/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild-register/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "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.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "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" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-airbnb": { + "version": "19.0.4", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz", + "integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==", + "dev": true, + "dependencies": { + "eslint-config-airbnb-base": "^15.0.0", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5" + }, + "engines": { + "node": "^10.12.0 || ^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.28.0", + "eslint-plugin-react-hooks": "^4.3.0" + } + }, + "node_modules/eslint-config-airbnb-base": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", + "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", + "dev": true, + "dependencies": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5", + "semver": "^6.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "peerDependencies": { + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.2" + } + }, + "node_modules/eslint-config-airbnb-base/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-module-utils": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.9.0.tgz", + "integrity": "sha512-nOFOCaJG2pYqORjK19lqPqxMO/JpvdCZdPtNdxY3kvom3jTvkAbOvQvD8wuD0G8BYR0IGAGYDlzqWJOh/ybn2g==", + "dev": true, + "dependencies": { + "aria-query": "~5.1.3", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.9.1", + "axobject-query": "~3.1.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "es-iterator-helpers": "^1.0.19", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.0" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "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 + } + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.34.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.4.tgz", + "integrity": "sha512-Np+jo9bUwJNxCsT12pXtrGhJgT3T44T1sHhn1Ssr42XFn8TES0267wPGo5nNrMHi8qkyimDAX2BUmkf9pSaVzA==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.toreversed": "^1.1.2", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.19", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.8", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.0", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.11", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", + "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-react/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-storybook": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-0.8.0.tgz", + "integrity": "sha512-CZeVO5EzmPY7qghO2t64oaFM+8FTaD4uzOEjHKp516exyTKo+skKAL9GI3QALS2BXhyALJjNtwbmr1XinGE8bA==", + "dev": true, + "dependencies": { + "@storybook/csf": "^0.0.1", + "@typescript-eslint/utils": "^5.62.0", + "requireindex": "^1.2.0", + "ts-dedent": "^2.2.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "eslint": ">=6" + } + }, + "node_modules/eslint-plugin-storybook/node_modules/@storybook/csf": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.0.1.tgz", + "integrity": "sha512-USTLkZze5gkel8MYCujSRBVIrUQ3YPBrLOx7GNk/0wttvVtlzWXAq9eLbQ4p/NicGxP+3T7KPEMVV//g+yubpw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.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" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-parse": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz", + "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==" + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fd-package-json": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fd-package-json/-/fd-package-json-1.2.0.tgz", + "integrity": "sha512-45LSPmWf+gC5tdCQMNH4s9Sr00bIkiD9aN7dc5hqkrEw1geRYyDQS1v1oMHAW3ysfxfndqGsrDREHHjNNbKUfA==", + "dev": true, + "dependencies": { + "walk-up-path": "^3.0.1" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/filesize": { + "version": "10.1.4", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.1.4.tgz", + "integrity": "sha512-ryBwPIIeErmxgPnm6cbESAzXjuEFubs+yKYLBZvg3CaiNcmkJChoOGcBSrZ6IwkMwPABwPpVXE6IlNdGJJrvEg==", + "dev": true, + "engines": { + "node": ">= 10.4.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "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" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flat-cache/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/flat-cache/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flat-cache/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/flow-parser": { + "version": "0.239.1", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.239.1.tgz", + "integrity": "sha512-topOrETNxJ6T2gAnQiWqAlzGPj8uI2wtmNOlDIMNB+qyvGJZ6R++STbUOTAYmvPhOMz2gXnXPH0hOvURYmrBow==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/foreground-child": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", + "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-9.0.2.tgz", + "integrity": "sha512-Uochze2R8peoN1XqlSi/rGUkDQpRogtLFocP9+PGu68zk1BDAKXfdeCdyVZpgTk8V8WFVQXdEz426VKjXLO1Gg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cosmiconfig": "^8.2.0", + "deepmerge": "^4.2.2", + "fs-extra": "^10.0.0", + "memfs": "^3.4.1", + "minimatch": "^3.0.4", + "node-abort-controller": "^3.0.1", + "schema-utils": "^3.1.1", + "semver": "^7.3.5", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">=12.13.0", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "typescript": ">3.6.0", + "webpack": "^5.11.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/giget": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/giget/-/giget-1.2.3.tgz", + "integrity": "sha512-8EHPljDvs7qKykr6uw8b+lqLiUc/vUg+KVTI0uND4s63TdsZM2Xus3mflvF0DDG9SiM4RlCkFGL+7aAjRmV7KA==", + "dev": true, + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.2.3", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.3", + "nypm": "^0.3.8", + "ohash": "^1.1.3", + "pathe": "^1.1.2", + "tar": "^6.2.0" + }, + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", + "dev": true + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globals": { + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.8.0.tgz", + "integrity": "sha512-VZAJ4cewHTExBWDHR6yptdIBlx9YSSZuwojj9Nt5mBRXQzrKakDsVKQ1J63sklLvzAJm0X5+RpO4i3Y2hcOnFw==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-heading-rank": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-heading-rank/-/hast-util-heading-rank-3.0.0.tgz", + "integrity": "sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.0.tgz", + "integrity": "sha512-OGkAxX1Ua3cbcW6EJ5pT/tslVb90uViVkcJ4ZZIMW/R33DX/AkcJcRrPebPwJkHYwlDHXz4aIwvAAaAdtrACFA==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-5.0.0.tgz", + "integrity": "sha512-puaGKdjdVVIFRtgIC2n5dt5bt0N5j6heXlAQZ4Do1MLjHmOT1gCE1Ogg7XZNeJlnOVHHsrZKGs5dfh+XwZ3XPw==", + "dev": true, + "dependencies": { + "html-minifier-terser": "^7.2.0", + "parse5": "^7.1.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/html-loader/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/html-loader/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/html-loader/node_modules/html-minifier-terser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", + "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "~5.3.2", + "commander": "^10.0.0", + "entities": "^4.4.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.15.1" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + } + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", + "integrity": "sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==", + "dev": true, + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "dev": true, + "engines": { + "node": ">=10.18" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-absolute-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-4.0.1.tgz", + "integrity": "sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", + "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-network-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", + "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dev": true, + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/iterator.prototype": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jscodeshift": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.15.2.tgz", + "integrity": "sha512-FquR7Okgmc4Sd0aEDwqho3rEiKR3BdvuG9jfdHjLJ6JQoWSMpavug3AoIfnfWhxFlf+5pzQh8qjqz0DWFrNQzA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.23.0", + "@babel/parser": "^7.23.0", + "@babel/plugin-transform-class-properties": "^7.22.5", + "@babel/plugin-transform-modules-commonjs": "^7.23.0", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.11", + "@babel/plugin-transform-optional-chaining": "^7.23.0", + "@babel/plugin-transform-private-methods": "^7.22.5", + "@babel/preset-flow": "^7.22.15", + "@babel/preset-typescript": "^7.23.0", + "@babel/register": "^7.22.15", + "babel-core": "^7.0.0-bridge.0", + "chalk": "^4.1.2", + "flow-parser": "0.*", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.4", + "neo-async": "^2.5.0", + "node-dir": "^0.1.17", + "recast": "^0.23.3", + "temp": "^0.8.4", + "write-file-atomic": "^2.3.0" + }, + "bin": { + "jscodeshift": "bin/jscodeshift.js" + }, + "peerDependencies": { + "@babel/preset-env": "^7.1.6" + }, + "peerDependenciesMeta": { + "@babel/preset-env": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "dev": true + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/launch-editor": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.0.tgz", + "integrity": "sha512-vJranOAJrI/llyWGRQqiDM+adrw+k83fvmmx3+nV47g3+36xM15jE+zyZ6Ffel02+xSvuM0b2GDRosXZkbb6wA==", + "dev": true, + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils-webpack-v4": { + "name": "loader-utils", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/loader-utils-webpack-v4/node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/map-or-similar": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz", + "integrity": "sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==", + "dev": true + }, + "node_modules/markdown-to-jsx": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.4.7.tgz", + "integrity": "sha512-0+ls1IQZdU6cwM1yu0ZjjiVWYtkbExSyUIFU2ZeDIFuZM1W42Mh4OlJ4nb4apX4H8smxDHRdFaoIVJGwfv5hkg==", + "dev": true, + "engines": { + "node": ">= 10" + }, + "peerDependencies": { + "react": ">= 0.14.0" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.9.3.tgz", + "integrity": "sha512-bsYSSnirtYTWi1+OPMFb0M048evMKyUYe0EbtuGQgq6BVQM1g1W8/KIUJCCvjgI/El0j6Q4WsmMiBwLUBSw8LA==", + "dev": true, + "dependencies": { + "@jsonjoy.com/json-pack": "^1.0.3", + "@jsonjoy.com/util": "^1.1.2", + "tree-dump": "^1.0.1", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">= 4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + } + }, + "node_modules/memoizerific": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/memoizerific/-/memoizerific-1.11.3.tgz", + "integrity": "sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==", + "dev": true, + "dependencies": { + "map-or-similar": "^1.5.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mlly": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.1.tgz", + "integrity": "sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "pathe": "^1.1.2", + "pkg-types": "^1.1.1", + "ufo": "^1.5.3" + } + }, + "node_modules/modify-source-webpack-plugin": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/modify-source-webpack-plugin/-/modify-source-webpack-plugin-4.1.0.tgz", + "integrity": "sha512-UaLQyFXoPWpWxkNUBFo9BotC20CCAGe7HEX9iKtB0P0MgNXgURf9TXUgNGuY5iVV5lDDQtcMjT2vneQWnNmwEw==", + "dependencies": { + "loader-utils-webpack-v4": "npm:loader-utils@^2.0.4", + "schema-utils": "^4.0.0" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + } + }, + "node_modules/modify-source-webpack-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/modify-source-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/modify-source-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/modify-source-webpack-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "dev": true + }, + "node_modules/node-dir": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", + "dev": true, + "dependencies": { + "minimatch": "^3.0.2" + }, + "engines": { + "node": ">= 0.10.5" + } + }, + "node_modules/node-dir/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/node-dir/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.4.tgz", + "integrity": "sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==", + "dev": true + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nypm": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.3.9.tgz", + "integrity": "sha512-BI2SdqqTHg2d4wJh8P9A1W+bslg33vOE9IZDY6eR2QC+Pu1iNBVZUqczrd43rJb+fMzHU7ltAYKsEFY/kHMFcw==", + "dev": true, + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.2.3", + "execa": "^8.0.1", + "pathe": "^1.1.2", + "pkg-types": "^1.1.1", + "ufo": "^1.5.3" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": "^14.16.0 || >=16.10.0" + } + }, + "node_modules/nypm/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/nypm/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/nypm/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nypm/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/objectorarray": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/objectorarray/-/objectorarray-1.0.5.tgz", + "integrity": "sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg==", + "dev": true + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/ohash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-1.1.3.tgz", + "integrity": "sha512-zuHHiGTYTA1sYJ/wZN+t5HKZaH23i4yI1HMwbuXm24Nid7Dv0KcuRlKoNKS9UNfAVSBlnGLcuQrnOKWOZoEGaw==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", + "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", + "dev": true, + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz", + "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "dev": true + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-types": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.1.3.tgz", + "integrity": "sha512-+JrgthZG6m3ckicaOB74TwQ+tBWsFl3qVQg7mN8ulwSOElJ7gBhKzj2VkCPnZ4NlF6kEquYU+RIYNVAvzd54UA==", + "dev": true, + "dependencies": { + "confbox": "^0.1.7", + "mlly": "^1.7.1", + "pathe": "^1.1.2" + } + }, + "node_modules/polished": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz", + "integrity": "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.17.8" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.4.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", + "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.1", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", + "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", + "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz", + "integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-colorful": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz", + "integrity": "sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==", + "dev": true, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/react-confetti": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-confetti/-/react-confetti-6.1.0.tgz", + "integrity": "sha512-7Ypx4vz0+g8ECVxr88W9zhcQpbeujJAVqL14ZnXJ3I23mOI9/oBVTQ3dkJhUmB0D6XOtCZEM6N0Gm9PMngkORw==", + "dev": true, + "dependencies": { + "tween-functions": "^1.2.0" + }, + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "react": "^16.3.0 || ^17.0.1 || ^18.0.0" + } + }, + "node_modules/react-docgen": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-7.0.3.tgz", + "integrity": "sha512-i8aF1nyKInZnANZ4uZrH49qn1paRgBZ7wZiCNBMnenlPzEv0mRl+ShpTVEI6wZNl8sSc79xZkivtgLKQArcanQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.18.9", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9", + "@types/babel__core": "^7.18.0", + "@types/babel__traverse": "^7.18.0", + "@types/doctrine": "^0.0.9", + "@types/resolve": "^1.20.2", + "doctrine": "^3.0.0", + "resolve": "^1.22.1", + "strip-indent": "^4.0.0" + }, + "engines": { + "node": ">=16.14.0" + } + }, + "node_modules/react-docgen-typescript": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-2.2.2.tgz", + "integrity": "sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==", + "dev": true, + "peerDependencies": { + "typescript": ">= 4.3.x" + } + }, + "node_modules/react-docgen/node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-element-to-jsx-string": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/react-element-to-jsx-string/-/react-element-to-jsx-string-15.0.0.tgz", + "integrity": "sha512-UDg4lXB6BzlobN60P8fHWVPX3Kyw8ORrTeBtClmIlGdkOOE+GYQSFvmEU5iLLpwp/6v42DINwNcwOhOLfQ//FQ==", + "dev": true, + "dependencies": { + "@base2/pretty-print-object": "1.0.1", + "is-plain-object": "5.0.0", + "react-is": "18.1.0" + }, + "peerDependencies": { + "react": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0", + "react-dom": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0" + } + }, + "node_modules/react-element-to-jsx-string/node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-element-to-jsx-string/node_modules/react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-router": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.24.1.tgz", + "integrity": "sha512-PTXFXGK2pyXpHzVo3rR9H7ip4lSPZZc0bHG5CARmj65fTT6qG7sTngmb6lcYu1gf3y/8KxORoy9yn59pGpCnpg==", + "dependencies": { + "@remix-run/router": "1.17.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.24.1.tgz", + "integrity": "sha512-U19KtXqooqw967Vw0Qcn5cOvrX5Ejo9ORmOtJMzYWtCT4/WOfFLIZGGsVLxcd9UkBO0mSTZtXqhZBsWlHr7+Sg==", + "dependencies": { + "@remix-run/router": "1.17.1", + "react-router": "6.24.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/recast": { + "version": "0.23.9", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.9.tgz", + "integrity": "sha512-Hx/BGIbwj+Des3+xy5uAtAbdCyqK9y9wbBcDFDYanLS9JnMqf7OeF87HQwUimE87OEc72mr6tkKUKMBBL+hF9Q==", + "dev": true, + "dependencies": { + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/redent/node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dev": true, + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/rehype-external-links": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rehype-external-links/-/rehype-external-links-3.0.0.tgz", + "integrity": "sha512-yp+e5N9V3C6bwBeAC4n796kc86M4gJCdlVhiMTxIrJG5UHDMh+PJANf9heqORJbt1nrCbDwIlAZKjANIaVBbvw==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-is-element": "^3.0.0", + "is-absolute-url": "^4.0.0", + "space-separated-tokens": "^2.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-slug": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/rehype-slug/-/rehype-slug-6.0.0.tgz", + "integrity": "sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "github-slugger": "^2.0.0", + "hast-util-heading-rank": "^3.0.0", + "hast-util-to-string": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dev": true, + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requireindex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", + "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", + "dev": true, + "engines": { + "node": ">=0.10.5" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", + "integrity": "sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": "14 >=14.20 || 16 >=16.20 || >=18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-applescript": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", + "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/spdy-transport/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/spdy-transport/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/spdy/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/spdy/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/storybook": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-8.2.2.tgz", + "integrity": "sha512-xDT9gyzAEFQNeK7P+Mj/8bNzN+fbm6/4D6ihdSzmczayjydpNjMs74HDHMY6S4Bfu6tRVyEK2ALPGnr6ZVofBA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/types": "^7.24.0", + "@storybook/codemod": "8.2.2", + "@storybook/core": "8.2.2", + "@types/semver": "^7.3.4", + "@yarnpkg/fslib": "2.10.3", + "@yarnpkg/libzip": "2.3.0", + "chalk": "^4.1.0", + "commander": "^6.2.1", + "cross-spawn": "^7.0.3", + "detect-indent": "^6.1.0", + "envinfo": "^7.7.3", + "execa": "^5.0.0", + "fd-package-json": "^1.2.0", + "find-up": "^5.0.0", + "fs-extra": "^11.1.0", + "giget": "^1.0.0", + "globby": "^14.0.1", + "jscodeshift": "^0.15.1", + "leven": "^3.1.0", + "ora": "^5.4.1", + "prettier": "^3.1.1", + "prompts": "^2.4.0", + "semver": "^7.3.7", + "strip-json-comments": "^3.0.1", + "tempy": "^3.1.0", + "tiny-invariant": "^1.3.1", + "ts-dedent": "^2.0.0" + }, + "bin": { + "getstorybook": "bin/index.cjs", + "sb": "bin/index.cjs", + "storybook": "bin/index.cjs" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/storybook/node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/storybook/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/storybook/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/storybook/node_modules/globby": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", + "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", + "dev": true, + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/storybook/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/storybook/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/storybook/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/storybook/node_modules/path-type": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/storybook/node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/string.prototype.includes": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.0.tgz", + "integrity": "sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz", + "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-loader": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz", + "integrity": "sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/swc-loader": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/swc-loader/-/swc-loader-0.2.6.tgz", + "integrity": "sha512-9Zi9UP2YmDpgmQVbyOPJClY0dwf58JDyDMQ7uRc4krmc72twNI2fvlBWHLqVekBpPc7h5NJkGVT1zNDxFrqhvg==", + "dev": true, + "dependencies": { + "@swc/counter": "^0.1.3" + }, + "peerDependencies": { + "@swc/core": "^1.2.147", + "webpack": ">=2" + } + }, + "node_modules/synckit": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", + "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/telejson": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/telejson/-/telejson-7.2.0.tgz", + "integrity": "sha512-1QTEcJkJEhc8OnStBx/ILRu5J2p0GjvWsBx56bmZRqnrkdBMUe+nX92jxV+p3dB4CP6PZCdJMQJwCggkNBMzkQ==", + "dev": true, + "dependencies": { + "memoizerific": "^1.11.3" + } + }, + "node_modules/temp": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz", + "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==", + "dev": true, + "dependencies": { + "rimraf": "~2.6.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/temp-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-3.0.0.tgz", + "integrity": "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==", + "dev": true, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/temp/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/temp/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/temp/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/temp/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/tempy": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-3.1.0.tgz", + "integrity": "sha512-7jDLIdD2Zp0bDe5r3D2qtkd1QOCacylBuL7oa4udvN6v2pqr4+LcCr67C8DR1zkpaZ8XosF5m1yQSabKAW6f2g==", + "dev": true, + "dependencies": { + "is-stream": "^3.0.0", + "temp-dir": "^3.0.0", + "type-fest": "^2.12.2", + "unique-string": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.31.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.2.tgz", + "integrity": "sha512-LGyRZVFm/QElZHy/CPr/O4eNZOZIzsrQ92y4v9UJe/pFJjypje2yI3C2FmPtvUEnhadlSbmG2nXtdcjHOjCfxw==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/thingies": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", + "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", + "dev": true, + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "tslib": "^2" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "dev": true + }, + "node_modules/tinyspy": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", + "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tree-dump": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", + "integrity": "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==", + "dev": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "dev": true, + "engines": { + "node": ">=6.10" + } + }, + "node_modules/ts-loader": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", + "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-loader/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "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" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tween-functions": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tween-functions/-/tween-functions-1.2.0.tgz", + "integrity": "sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.16.0.tgz", + "integrity": "sha512-kaVRivQjOzuoCXU6+hLnjo3/baxyzWVO5GrnExkFzETRYJKVHYkrJglOu2OCm8Hi9RPDWX1PTNNTpU5KRV0+RA==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "7.16.0", + "@typescript-eslint/parser": "7.16.0", + "@typescript-eslint/utils": "7.16.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.0.tgz", + "integrity": "sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/typescript-estree": "7.16.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/ufo": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.3.tgz", + "integrity": "sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==", + "dev": true + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unique-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "dev": true, + "dependencies": { + "crypto-random-string": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unplugin": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.11.0.tgz", + "integrity": "sha512-3r7VWZ/webh0SGgJScpWl2/MRCZK5d3ZYFcNaeci/GQ7Teop7zf0Nl2pUuz7G21BwPd9pcUPOC5KmJ2L3WgC5g==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "chokidar": "^3.6.0", + "webpack-sources": "^3.2.3", + "webpack-virtual-modules": "^0.6.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.3.tgz", + "integrity": "sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==", + "dev": true, + "dependencies": { + "punycode": "^1.4.1", + "qs": "^6.11.2" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true + }, + "node_modules/url/node_modules/qs": { + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.3.tgz", + "integrity": "sha512-AWJm14H1vVaO/iNZ4/hO+HyaTehuy9nRqVdkTqlJt0HWvBiBIEXFmb4C0DGeYo3Xes9rrEW+TxHsaigCbN5ICQ==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/walk-up-path": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-3.0.1.tgz", + "integrity": "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==", + "dev": true + }, + "node_modules/watchpack": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", + "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webpack": { + "version": "5.93.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.93.0.tgz", + "integrity": "sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.7.1", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.2.1.tgz", + "integrity": "sha512-hRLz+jPQXo999Nx9fXVdKlg/aehsw1ajA9skAneGmT03xwmyuhvF93p6HUKKbWhXdcERtGTzUCtIQr+2IQegrA==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^4.6.0", + "mime-types": "^2.1.31", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.0.4.tgz", + "integrity": "sha512-dljXhUgx3HqKP2d8J/fUMvhxGhzjeNVarDLcbO/EWMSgRizDkxHQDZQaLFL5VJY9tRBj2Gz+rvCEYYvhbqPHNA==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.13", + "@types/connect-history-api-fallback": "^1.5.4", + "@types/express": "^4.17.21", + "@types/serve-index": "^1.9.4", + "@types/serve-static": "^1.15.5", + "@types/sockjs": "^0.3.36", + "@types/ws": "^8.5.10", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.2.1", + "chokidar": "^3.6.0", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.4.0", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.1.0", + "launch-editor": "^2.6.1", + "open": "^10.0.3", + "p-retry": "^6.2.0", + "rimraf": "^5.0.5", + "schema-utils": "^4.2.0", + "selfsigned": "^2.4.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^7.1.0", + "ws": "^8.16.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-server/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-hot-middleware": { + "version": "2.26.1", + "resolved": "https://registry.npmjs.org/webpack-hot-middleware/-/webpack-hot-middleware-2.26.1.tgz", + "integrity": "sha512-khZGfAeJx6I8K9zKohEWWYN6KDlVw2DHownoe+6Vtwj1LP9WFgegXnVMSkZ/dBEBtXFwrkkydsaPFlB7f8wU2A==", + "dev": true, + "dependencies": { + "ansi-html-community": "0.0.8", + "html-entities": "^2.1.0", + "strip-ansi": "^6.0.0" + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dev": true, + "dependencies": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/HDesign/package.json b/HDesign/package.json new file mode 100644 index 000000000..5abaa6227 --- /dev/null +++ b/HDesign/package.json @@ -0,0 +1,66 @@ +{ + "name": "haengdong-design", + "version": "1.0.0", + "description": "", + "type": "module", + "scripts": { + "start": "webpack serve ", + "build": "webpack --mode production", + "storybook": "storybook dev -p 6006", + "lint": "eslint 'lib/**/*.{js,jsx,ts,tsx}'", + "format": "prettier --write 'lib/**/*.{js,jsx,ts,tsx,json,css,scss,md}'", + "build-storybook": "storybook build" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@chromatic-com/storybook": "^1.6.1", + "@eslint/compat": "^1.1.0", + "@eslint/js": "^9.6.0", + "@storybook/addon-essentials": "^8.2.2", + "@storybook/addon-interactions": "^8.2.2", + "@storybook/addon-links": "^8.2.2", + "@storybook/addon-onboarding": "^8.2.2", + "@storybook/addon-webpack5-compiler-swc": "^1.0.4", + "@storybook/blocks": "^8.2.2", + "@storybook/react": "^8.2.2", + "@storybook/react-webpack5": "^8.2.2", + "@storybook/test": "^8.2.2", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^7.16.0", + "@typescript-eslint/parser": "^7.16.0", + "eslint": "^8.57.0", + "eslint-config-airbnb": "^19.0.4", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-jsx-a11y": "^6.9.0", + "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-react": "^7.34.4", + "eslint-plugin-react-hooks": "^4.6.2", + "eslint-plugin-storybook": "^0.8.0", + "fork-ts-checker-webpack-plugin": "^9.0.2", + "globals": "^15.8.0", + "html-loader": "^5.0.0", + "html-webpack-plugin": "^5.6.0", + "prettier": "3.3.2", + "storybook": "^8.2.2", + "ts-loader": "^9.5.1", + "typescript": "^5.5.3", + "typescript-eslint": "^7.16.0", + "webpack": "^5.93.0", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^5.0.4" + }, + "dependencies": { + "@emotion/react": "^11.11.4", + "modify-source-webpack-plugin": "^4.1.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.24.1" + }, + "engines": { + "npm": ">=10.7.0", + "node": ">=20.15.1" + } +} diff --git a/HDesign/tsconfig.json b/HDesign/tsconfig.json new file mode 100644 index 000000000..4f0fd007a --- /dev/null +++ b/HDesign/tsconfig.json @@ -0,0 +1,43 @@ +{ + "compilerOptions": { + "sourceMap": true, + "module": "ES2020", + "target": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "useDefineForClassFields": true, + "removeComments": true, + "skipLibCheck": true, + + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + + // "types": ["jest"], + "esModuleInterop": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictBindCallApply": true, + "strictPropertyInitialization": true, + "noImplicitAny": true, + "noImplicitThis": true, + "alwaysStrict": true, + "noImplicitReturns": true, + "forceConsistentCasingInFileNames": true, + "jsxImportSource": "@emotion/react", + + "baseUrl": "./", + "paths": { + "components/*": ["lib/components/*"] + }, + "outDir": "./dist" + }, + "include": ["lib"] +} diff --git a/HDesign/webpack.config.js b/HDesign/webpack.config.js new file mode 100644 index 000000000..7077a6f5a --- /dev/null +++ b/HDesign/webpack.config.js @@ -0,0 +1,48 @@ +import path from 'path'; +import {fileURLToPath} from 'url'; + +import HtmlWebpackPlugin from 'html-webpack-plugin'; +import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; +import {ModifySourcePlugin, ConcatOperation} from 'modify-source-webpack-plugin'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +export default { + mode: 'development', + entry: './lib/index.tsx', + resolve: { + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }, + output: { + path: path.join(__dirname, 'dist'), + filename: 'bundle.min.js', + }, + module: { + rules: [ + { + test: /\.tsx?$/, + loader: 'ts-loader', + exclude: /node_modules/, + }, + ], + }, + plugins: [ + new HtmlWebpackPlugin({ + template: './index.html', + }), + new ForkTsCheckerWebpackPlugin(), + new ModifySourcePlugin({ + rules: [ + { + test: /\.tsx$/i, + operations: [new ConcatOperation('start', '/** @jsxImportSource @emotion/react */\n\n')], + }, + ], + }), + ], + devServer: { + port: 3000, + hot: true, + }, +}; From 3d7044380e32499d3de44c2c847aa4a0533b7779 Mon Sep 17 00:00:00 2001 From: Soyeon Choe Date: Tue, 16 Jul 2024 01:58:54 +0900 Subject: [PATCH 015/178] =?UTF-8?q?feat:=20theme,=20token=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> --- HDesign/lib/theme/GlobalStyle.ts | 121 ++++++++++++++++++++++++++ HDesign/lib/theme/HDesignProvider.tsx | 35 ++++++++ HDesign/lib/theme/theme.type.ts | 7 ++ HDesign/lib/token/colors.ts | 43 +++++++++ HDesign/lib/token/typography.ts | 67 ++++++++++++++ 5 files changed, 273 insertions(+) create mode 100644 HDesign/lib/theme/GlobalStyle.ts create mode 100644 HDesign/lib/theme/HDesignProvider.tsx create mode 100644 HDesign/lib/theme/theme.type.ts create mode 100644 HDesign/lib/token/colors.ts create mode 100644 HDesign/lib/token/typography.ts diff --git a/HDesign/lib/theme/GlobalStyle.ts b/HDesign/lib/theme/GlobalStyle.ts new file mode 100644 index 000000000..08cd8094e --- /dev/null +++ b/HDesign/lib/theme/GlobalStyle.ts @@ -0,0 +1,121 @@ +import {css} from '@emotion/react'; + +export const GlobalStyle = css` + *:where(:not(html, iframe, canvas, img, svg, video, audio):not(svg *, symbol *)) { + all: unset; + display: revert; + } + + /* Preferred box-sizing value */ + *, + *::before, + *::after { + box-sizing: border-box; + } + + /* Fix mobile Safari increase font-size on landscape mode */ + html { + -moz-text-size-adjust: none; + -webkit-text-size-adjust: none; + text-size-adjust: none; + } + + /* Reapply the pointer cursor for anchor tags */ + a, + button { + cursor: revert; + } + + /* Remove list styles (bullets/numbers) */ + ol, + ul, + menu, + summary { + list-style: none; + } + + /* For images to not be able to exceed their container */ + img { + max-inline-size: 100%; + max-block-size: 100%; + } + + /* Removes spacing between cells in tables */ + table { + border-collapse: collapse; + } + + /* Safari - solving issue when using user-select:none on the text input doesn't working */ + input, + textarea { + -webkit-user-select: auto; + } + + /* Revert the 'white-space' property for textarea elements on Safari */ + textarea { + white-space: revert; + } + + /* Minimum style to allow to style meter element */ + meter { + -webkit-appearance: revert; + appearance: revert; + } + + /* Preformatted text - use only for this feature */ + :where(pre) { + all: revert; + box-sizing: border-box; + } + + /* Fix the feature of 'hidden' attribute. + display: revert; revert to element instead of attribute */ + :where([hidden]) { + display: none; + } + + /* Revert for bug in Chromium browsers + - Fix for the content editable attribute will work properly. + - webkit-user-select: auto; added for Safari in case of using user-select:none on wrapper element */ + :where([contenteditable]:not([contenteditable='false'])) { + -moz-user-modify: read-write; + -webkit-user-modify: read-write; + overflow-wrap: break-word; + -webkit-line-break: after-white-space; + -webkit-user-select: auto; + } + + /* Apply back the draggable feature - exist only in Chromium and Safari */ + :where([draggable='true']) { + -webkit-user-drag: element; + } + + /* Revert Modal native behavior */ + :where(dialog:modal) { + all: revert; + box-sizing: border-box; + } + + /* Remove details summary webkit styles */ + ::-webkit-details-marker { + display: none; + } + + /* Chrome, Safari, Edge, Opera */ + input::-webkit-outer-spin-button, + input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; + } + + /* Firefox */ + input[type='number'] { + -moz-appearance: textfield; + } + + #root { + display: flex; + justify-content: center; + background-color: #eeeeee; + } +`; diff --git a/HDesign/lib/theme/HDesignProvider.tsx b/HDesign/lib/theme/HDesignProvider.tsx new file mode 100644 index 000000000..d196dba2d --- /dev/null +++ b/HDesign/lib/theme/HDesignProvider.tsx @@ -0,0 +1,35 @@ +import React, {createContext, useContext, useState, ReactNode} from 'react'; +import {Global} from '@emotion/react'; +import {COLORS} from '../token/colors'; +import {TYPOGRAPHY} from '../token/typography'; +import {Theme} from './theme.type'; +import {GlobalStyle} from './GlobalStyle'; + +interface ThemeContextProps { + theme: Theme; +} + +const defaultTheme: Theme = { + colors: COLORS, + typography: TYPOGRAPHY, +}; + +const ThemeContext = createContext(undefined); + +export const HDesignProvider: React.FC<{children: ReactNode}> = ({children}) => { + const [theme, _] = useState(defaultTheme); + return ( + + + {children} + + ); +}; + +export const useTheme = (): ThemeContextProps => { + const context = useContext(ThemeContext); + if (!context) { + throw new Error('useTheme must be used within a HDesignProvider'); + } + return context; +}; diff --git a/HDesign/lib/theme/theme.type.ts b/HDesign/lib/theme/theme.type.ts new file mode 100644 index 000000000..73c0f8359 --- /dev/null +++ b/HDesign/lib/theme/theme.type.ts @@ -0,0 +1,7 @@ +import {ColorTokens} from '../token/colors'; +import {TypographyTokens} from '../token/typography'; + +export interface Theme { + colors: ColorTokens; + typography: TypographyTokens; +} diff --git a/HDesign/lib/token/colors.ts b/HDesign/lib/token/colors.ts new file mode 100644 index 000000000..668f1c272 --- /dev/null +++ b/HDesign/lib/token/colors.ts @@ -0,0 +1,43 @@ +const PRIMITIVE_COLORS = { + white: '#FFFFFF', + purple: { + 50: '#f4e8ff', + 100: '#e0c7fe', + 200: '#cba0fe', + 300: '#b575ff', + 400: '#a350fd', + 500: '#8f2bf3', + 600: '#8425ec', + 700: '#7519e3', + 800: '#6712db', + 900: '#5100cd', + }, + gray: { + 50: '#F9F8FD', + 100: '#F1F0F5', + 200: '#E7E6EB', + 300: '#D6D5DA', + 400: '#B2B1B6', + 500: '#929195', + 600: '#6A696D', + 700: '#56555A', + 800: '#38373B', + 900: '#18171B', + }, +}; + +type Color = string; + +export type ColorTokens = Record; + +// TODO: (@soha) 대괄호 사용에 대해 논의 +export const COLORS: ColorTokens = { + white: PRIMITIVE_COLORS.white, + black: PRIMITIVE_COLORS.gray[700], + primary: PRIMITIVE_COLORS.purple[300], + onPrimary: PRIMITIVE_COLORS.white, + secondary: PRIMITIVE_COLORS.purple[50], + onSecondary: PRIMITIVE_COLORS.purple[600], + tertiary: PRIMITIVE_COLORS.gray[200], + onTertiary: PRIMITIVE_COLORS.gray[700], +}; diff --git a/HDesign/lib/token/typography.ts b/HDesign/lib/token/typography.ts new file mode 100644 index 000000000..c88d61ea9 --- /dev/null +++ b/HDesign/lib/token/typography.ts @@ -0,0 +1,67 @@ +type Typography = Record; +export type TypographyTokens = Record; + +export const TYPOGRAPHY: TypographyTokens = { + head: { + fontFamily: 'Pretendard', + fontSize: '3rem', + lineHeight: '1.5', + fontWeight: '700', + }, + title: { + fontFamily: 'Pretendard', + fontSize: '2rem', + lineHeight: '1.5', + fontWeight: '700', + }, + subTitle: { + fontFamily: 'Pretendard', + fontSize: '1.5rem', + lineHeight: '1.5', + fontWeight: '700', + }, + bodyBold: { + fontFamily: 'Pretendard', + fontSize: '1rem', + lineHeight: '1.5', + fontWeight: '700', + }, + body: { + fontFamily: 'Pretendard', + fontSize: '1rem', + lineHeight: '1.5', + fontWeight: '400', + }, + smallBodyBold: { + fontFamily: 'Pretendard', + fontSize: '0.875rem', + lineHeight: '1.5', + fontWeight: '700', + }, + smallBody: { + fontFamily: 'Pretendard', + fontSize: '0.875rem', + lineHeight: '1.5', + fontWeight: '400', + }, + captionBold: { + fontFamily: 'Pretendard', + fontSize: '0.75rem', + lineHeight: '1.5', + fontWeight: '700', + }, + caption: { + fontFamily: 'Pretendard', + fontSize: '0.75rem', + lineHeight: '1.5', + fontWeight: '400', + }, + tiny: { + fontFamily: 'Pretendard', + fontSize: '0.625rem', + lineHeight: '1.5', + fontWeight: '400', + }, +}; + +export default TYPOGRAPHY; From 9cf6fd53a6c2036cbbd54b625b2631c786d4b0c4 Mon Sep 17 00:00:00 2001 From: Soyeon Choe Date: Tue, 16 Jul 2024 01:59:39 +0900 Subject: [PATCH 016/178] =?UTF-8?q?chore:=20storybook=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> --- HDesign/.gitignore | 1 + HDesign/.storybook/main.ts | 2 +- .../.storybook/{preview.ts => preview.tsx} | 10 +++ HDesign/package-lock.json | 71 +++++++++++-------- HDesign/package.json | 2 +- 5 files changed, 56 insertions(+), 30 deletions(-) rename HDesign/.storybook/{preview.ts => preview.tsx} (54%) diff --git a/HDesign/.gitignore b/HDesign/.gitignore index afd0485d1..b98928456 100644 --- a/HDesign/.gitignore +++ b/HDesign/.gitignore @@ -7,5 +7,6 @@ dist .env +storybook-static *storybook.log .DS_Store diff --git a/HDesign/.storybook/main.ts b/HDesign/.storybook/main.ts index dcdd7bf09..30eb7b35e 100644 --- a/HDesign/.storybook/main.ts +++ b/HDesign/.storybook/main.ts @@ -1,7 +1,7 @@ import type {StorybookConfig} from '@storybook/react-webpack5'; const config: StorybookConfig = { - stories: ['../stories/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'], + stories: ['../lib/**/*.mdx', '../lib/**/*.stories.@(js|jsx|mjs|ts|tsx)'], addons: [ '@storybook/addon-webpack5-compiler-swc', '@storybook/addon-onboarding', diff --git a/HDesign/.storybook/preview.ts b/HDesign/.storybook/preview.tsx similarity index 54% rename from HDesign/.storybook/preview.ts rename to HDesign/.storybook/preview.tsx index a66ea2ee6..921253ef6 100644 --- a/HDesign/.storybook/preview.ts +++ b/HDesign/.storybook/preview.tsx @@ -1,4 +1,7 @@ +import React from 'react'; + import type {Preview} from '@storybook/react'; +import {HDesignProvider} from '../lib/theme/HDesignProvider'; const preview: Preview = { parameters: { @@ -9,6 +12,13 @@ const preview: Preview = { }, }, }, + decorators: [ + Story => ( + + + + ), + ], }; export default preview; diff --git a/HDesign/package-lock.json b/HDesign/package-lock.json index 0d86a87a3..7fea2f72f 100644 --- a/HDesign/package-lock.json +++ b/HDesign/package-lock.json @@ -26,7 +26,7 @@ "@storybook/addon-webpack5-compiler-swc": "^1.0.4", "@storybook/blocks": "^8.2.2", "@storybook/react": "^8.2.2", - "@storybook/react-webpack5": "^8.2.2", + "@storybook/react-webpack5": "^8.2.3", "@storybook/test": "^8.2.2", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", @@ -3544,12 +3544,12 @@ } }, "node_modules/@storybook/builder-webpack5": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/builder-webpack5/-/builder-webpack5-8.2.2.tgz", - "integrity": "sha512-ud6a3pRusbC/TvT1ed15INxSivyL2y2zI61O/MWQZmM8sZOIC6ObdHLtzU4+535IIqiXhPoQ/QiOBbejqjgZvw==", + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@storybook/builder-webpack5/-/builder-webpack5-8.2.3.tgz", + "integrity": "sha512-yU9rtcVpo12vD8m/nbdepyJ09K937ZnSsrvIM9XfzbxXA/+p4Cov9Rjg1VfoWyRd1ApxaztSktQlawBlb6bKEA==", "dev": true, "dependencies": { - "@storybook/core-webpack": "8.2.2", + "@storybook/core-webpack": "8.2.3", "@types/node": "^18.0.0", "@types/semver": "^7.3.4", "browser-assert": "^1.2.1", @@ -3582,7 +3582,7 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.2.2" + "storybook": "^8.2.3" }, "peerDependenciesMeta": { "typescript": { @@ -3879,9 +3879,9 @@ } }, "node_modules/@storybook/core-webpack": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/core-webpack/-/core-webpack-8.2.2.tgz", - "integrity": "sha512-M5wzgNbotVXcfo7WkXIuDxcBl7tTjnQ27lmlSBk+cu63pDvNn4UMDan621FcvxWq2DbjgIj+PASZ4DzM5O+ovA==", + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@storybook/core-webpack/-/core-webpack-8.2.3.tgz", + "integrity": "sha512-0M4mJM6i4Oqp1javRMg/8wJW7VJ6p6Z8GKp6evfHLEWZAzdnexQIkPd5FFaDlFXbQNH1H0oJ+6ei4nIBtEegKg==", "dev": true, "dependencies": { "@types/node": "^18.0.0", @@ -3892,7 +3892,7 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^8.2.2" + "storybook": "^8.2.3" } }, "node_modules/@storybook/core-webpack/node_modules/@types/node": { @@ -3976,13 +3976,13 @@ } }, "node_modules/@storybook/preset-react-webpack": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/preset-react-webpack/-/preset-react-webpack-8.2.2.tgz", - "integrity": "sha512-GJkDtw4Ac8icD66fotGXYE3rmZkIwASpNLOeGzyP4eMMNaf5vlvTDxwkY551cGbnA5P7r4UkGjDiWinB9XE4VQ==", + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@storybook/preset-react-webpack/-/preset-react-webpack-8.2.3.tgz", + "integrity": "sha512-i886+vCMGlpFgOAOIg6BxSHgt38MXS6gqNX8Z65KVVIlI6i/9WqEQeHYfukbdGvVZ96cYWmdrnqUieIIkdCdBw==", "dev": true, "dependencies": { - "@storybook/core-webpack": "8.2.2", - "@storybook/react": "8.2.2", + "@storybook/core-webpack": "8.2.3", + "@storybook/react": "8.2.3", "@storybook/react-docgen-typescript-plugin": "1.0.6--canary.9.0c3f3b7.0", "@types/node": "^18.0.0", "@types/semver": "^7.3.4", @@ -4005,7 +4005,7 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^8.2.2" + "storybook": "^8.2.3" }, "peerDependenciesMeta": { "typescript": { @@ -4124,13 +4124,13 @@ } }, "node_modules/@storybook/react": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/react/-/react-8.2.2.tgz", - "integrity": "sha512-U4p/RV78yhjEwEzem8U7wE5/3sSpnqreGsPdAHMCIHd69e9tVeF0rwrTJGp917RClPjBKgEcfelCuvOlby4MrA==", + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-8.2.3.tgz", + "integrity": "sha512-818F6pJWFBiwG0r6DiUVrV+qndwbIso2gtgJoituBgIJO2eIzNmkPNSsckbaR7u+FpE4dWiIIhmDVZSnRwvDlA==", "dev": true, "dependencies": { "@storybook/global": "^5.0.0", - "@storybook/react-dom-shim": "8.2.2", + "@storybook/react-dom-shim": "8.2.3", "@types/escodegen": "^0.0.6", "@types/estree": "^0.0.51", "@types/node": "^18.0.0", @@ -4157,7 +4157,7 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^8.2.2", + "storybook": "^8.2.3", "typescript": ">= 4.2.x" }, "peerDependenciesMeta": { @@ -4224,14 +4224,14 @@ } }, "node_modules/@storybook/react-webpack5": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/react-webpack5/-/react-webpack5-8.2.2.tgz", - "integrity": "sha512-JPR2Lp88KbfRWgnAd4lKFRKuc9Up6YeqbaDb6sptOXXzDM4nOhlRXKqp2tIqyhfiKp3wmu3PksixqD8f8VS9CA==", + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@storybook/react-webpack5/-/react-webpack5-8.2.3.tgz", + "integrity": "sha512-lcm73r8S5Uy2ENuFDSR07fW+KRSYGNcrF53VItP+rgFZHrOm7gaeebrjSIA6r4tQwdd9218VaqpQGFrKAURS2w==", "dev": true, "dependencies": { - "@storybook/builder-webpack5": "8.2.2", - "@storybook/preset-react-webpack": "8.2.2", - "@storybook/react": "8.2.2", + "@storybook/builder-webpack5": "8.2.3", + "@storybook/preset-react-webpack": "8.2.3", + "@storybook/react": "8.2.3", "@types/node": "^18.0.0" }, "engines": { @@ -4244,7 +4244,7 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^8.2.2", + "storybook": "^8.2.3", "typescript": ">= 4.2.x" }, "peerDependenciesMeta": { @@ -4262,6 +4262,21 @@ "undici-types": "~5.26.4" } }, + "node_modules/@storybook/react/node_modules/@storybook/react-dom-shim": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-8.2.3.tgz", + "integrity": "sha512-N8AsM6N1S867GGWt2J2q5oY5ryqxohh3y1HqNtjg+wXf5+RkTD6M2Cgqe6p+JHz81nDKyvvVzP60MvvDhY5VOA==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.2.3" + } + }, "node_modules/@storybook/react/node_modules/@types/estree": { "version": "0.0.51", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", diff --git a/HDesign/package.json b/HDesign/package.json index 5abaa6227..2e97b2ed8 100644 --- a/HDesign/package.json +++ b/HDesign/package.json @@ -25,7 +25,7 @@ "@storybook/addon-webpack5-compiler-swc": "^1.0.4", "@storybook/blocks": "^8.2.2", "@storybook/react": "^8.2.2", - "@storybook/react-webpack5": "^8.2.2", + "@storybook/react-webpack5": "^8.2.3", "@storybook/test": "^8.2.2", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", From 94b04b7bba988fa4ad5370e424e1f01db929f252 Mon Sep 17 00:00:00 2001 From: Soyeon Choe Date: Tue, 16 Jul 2024 01:59:58 +0900 Subject: [PATCH 017/178] =?UTF-8?q?feat:=20Button=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> --- .../lib/components/Button/Button.stories.tsx | 40 +++++++++++ HDesign/lib/components/Button/Button.style.ts | 69 +++++++++++++++++++ HDesign/lib/components/Button/Button.tsx | 18 +++++ HDesign/lib/components/Button/Button.type.ts | 16 +++++ 4 files changed, 143 insertions(+) create mode 100644 HDesign/lib/components/Button/Button.stories.tsx create mode 100644 HDesign/lib/components/Button/Button.style.ts create mode 100644 HDesign/lib/components/Button/Button.tsx create mode 100644 HDesign/lib/components/Button/Button.type.ts diff --git a/HDesign/lib/components/Button/Button.stories.tsx b/HDesign/lib/components/Button/Button.stories.tsx new file mode 100644 index 000000000..2e8b00bb3 --- /dev/null +++ b/HDesign/lib/components/Button/Button.stories.tsx @@ -0,0 +1,40 @@ +import type {Meta, StoryObj} from '@storybook/react'; + +import Button from './Button'; + +const meta = { + title: 'Components/Button', + component: Button, + tags: ['autodocs'], + parameters: { + layout: 'centered', + }, + argTypes: { + variants: { + description: '', + control: {type: 'select'}, + options: ['', 'primary', 'secondary', 'tertiary'], + }, + size: { + description: '', + control: {type: 'select'}, + options: ['', 'small', 'medium', 'large'], + }, + disabled: { + description: '', + control: {type: 'boolean'}, + }, + }, + args: { + variants: 'primary', + size: 'medium', + disabled: false, + children: 'button', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/lib/components/Button/Button.style.ts b/HDesign/lib/components/Button/Button.style.ts new file mode 100644 index 000000000..d9270b35c --- /dev/null +++ b/HDesign/lib/components/Button/Button.style.ts @@ -0,0 +1,69 @@ +import {css} from '@emotion/react'; +import {ButtonStyleProps, ButtonSize, ButtonVariants} from './Button.type'; +import {Theme} from '../../theme/theme.type'; + +export const buttonStyle = (props: Required) => { + return [ + getButtonDefaultStyle(props.theme), + getButtonSizeStyle(props.size), + getButtonVariantsStyle(props.variants, props.theme), + ]; +}; + +const getButtonDefaultStyle = (theme: Theme) => + css({ + display: 'flex', + lineHeight: '1', + + '&:disabled': { + backgroundColor: theme.colors.tertiary, + color: theme.colors.onPrimary, + }, + }); + +const getButtonSizeStyle = (size: ButtonSize) => { + const style = { + small: css({ + padding: '0.5rem 0.75rem', + borderRadius: '0.75rem', + fontFamily: 'Pretendard', + fontSize: '0.75rem', + fontWeight: '400', + }), + medium: css({ + padding: '0.75rem 1rem', + borderRadius: '1rem', + fontFamily: 'Pretendard', + fontSize: '1rem', + fontWeight: '700', + }), + large: css({ + padding: '1rem 1.5rem', + borderRadius: '1.25rem', + fontFamily: 'Pretendard', + fontSize: '1.25rem', + fontWeight: '700', + }), + }; + + return style[size]; +}; + +const getButtonVariantsStyle = (variants: ButtonVariants, theme: Theme) => { + const style = { + primary: css({ + backgroundColor: theme.colors.primary, + color: theme.colors.onPrimary, + }), + secondary: css({ + backgroundColor: theme.colors.secondary, + color: theme.colors.onSecondary, + }), + tertiary: css({ + backgroundColor: theme.colors.tertiary, + color: theme.colors.onTertiary, + }), + }; + + return style[variants]; +}; diff --git a/HDesign/lib/components/Button/Button.tsx b/HDesign/lib/components/Button/Button.tsx new file mode 100644 index 000000000..01474c0e8 --- /dev/null +++ b/HDesign/lib/components/Button/Button.tsx @@ -0,0 +1,18 @@ +/** @jsxImportSource @emotion/react */ +import React, {forwardRef} from 'react'; + +import {buttonStyle} from './Button.style'; + +import {ButtonProps} from './Button.type'; + +import {useTheme} from '../../theme/HDesignProvider'; + +export const Button: React.FC = forwardRef(function Button( + {variants = 'primary', size = 'medium', ...htmlProps}: ButtonProps, + ref, +) { + const {theme} = useTheme(); + return + + ); +}; + +export default Main; diff --git a/client/src/pages/Main/index.ts b/client/src/pages/Main/index.ts new file mode 100644 index 000000000..c3cce532e --- /dev/null +++ b/client/src/pages/Main/index.ts @@ -0,0 +1 @@ +export {default as MainPage} from './Main'; From 00d75e4b81239b573fdf4819cf2cdc4defc6575a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=84=ED=98=B8?= Date: Tue, 16 Jul 2024 01:00:56 +0900 Subject: [PATCH 024/178] =?UTF-8?q?feat:=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=ED=8D=BC?= =?UTF-8?q?=EB=B8=94=EB=A6=AC=EC=8B=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe --- client/src/pages/CreateEvent/CreateEvent.tsx | 26 ++++++++++++++++++++ client/src/pages/CreateEvent/index.ts | 1 + 2 files changed, 27 insertions(+) create mode 100644 client/src/pages/CreateEvent/CreateEvent.tsx create mode 100644 client/src/pages/CreateEvent/index.ts diff --git a/client/src/pages/CreateEvent/CreateEvent.tsx b/client/src/pages/CreateEvent/CreateEvent.tsx new file mode 100644 index 000000000..476418ead --- /dev/null +++ b/client/src/pages/CreateEvent/CreateEvent.tsx @@ -0,0 +1,26 @@ +import {useState} from 'react'; +import {useNavigate} from 'react-router-dom'; +import {ROUTER_URLS} from '../../constants/routerUrls'; + +const CreateEvent = () => { + const [eventTitle, setEventTitle] = useState(''); + const navigate = useNavigate(); + + const submitEventTitle = (event: React.FormEvent) => { + event.preventDefault(); + navigate(`${ROUTER_URLS.completeCreateEvent}?${new URLSearchParams({title: eventTitle})}`); + }; + + return ( +
+

행사 생성하기

+

시작할 행사 이름을 입력해 주세요.

+
+ setEventTitle(event.target.value)} /> + +
+
+ ); +}; + +export default CreateEvent; diff --git a/client/src/pages/CreateEvent/index.ts b/client/src/pages/CreateEvent/index.ts new file mode 100644 index 000000000..ac2c26d0c --- /dev/null +++ b/client/src/pages/CreateEvent/index.ts @@ -0,0 +1 @@ +export {default as CreateEventPage} from './CreateEvent'; From b287a347caab9cf20205c2dc1c9da154dc53e6b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=84=ED=98=B8?= Date: Tue, 16 Jul 2024 01:01:14 +0900 Subject: [PATCH 025/178] =?UTF-8?q?feat:=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EC=99=84=EB=A3=8C=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=ED=8D=BC=EB=B8=94=EB=A6=AC=EC=8B=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe --- .../CompleteCreateEvent.tsx | 34 +++++++++++++++++++ client/src/pages/CompleteCreateEvent/index.ts | 1 + 2 files changed, 35 insertions(+) create mode 100644 client/src/pages/CompleteCreateEvent/CompleteCreateEvent.tsx create mode 100644 client/src/pages/CompleteCreateEvent/index.ts diff --git a/client/src/pages/CompleteCreateEvent/CompleteCreateEvent.tsx b/client/src/pages/CompleteCreateEvent/CompleteCreateEvent.tsx new file mode 100644 index 000000000..d8fdf9735 --- /dev/null +++ b/client/src/pages/CompleteCreateEvent/CompleteCreateEvent.tsx @@ -0,0 +1,34 @@ +import {useEffect, useState} from 'react'; +import {useLocation, useNavigate} from 'react-router-dom'; +import {ROUTER_URLS} from '../../constants/routerUrls'; + +const CompleteCreateEvent = () => { + const [url, setUrl] = useState(''); + const navigate = useNavigate(); + const location = useLocation(); + + useEffect(() => { + const getUrl = async () => { + const eventTitle = location.search; + console.log(eventTitle); + + // const url = await fetch(); + setUrl('hangsapage'); + }; + + getUrl(); + }, []); + + return ( +
+

행사 개시

+

+ 행사가 성공적으로 개시됐어요 :) 행사 링크를 통해서 참여자 관리가 가능해요. 관리를 위해서 행사 관리 링크를 보관해 + 주세요. +

+ +
+ ); +}; + +export default CompleteCreateEvent; diff --git a/client/src/pages/CompleteCreateEvent/index.ts b/client/src/pages/CompleteCreateEvent/index.ts new file mode 100644 index 000000000..a1e4fa117 --- /dev/null +++ b/client/src/pages/CompleteCreateEvent/index.ts @@ -0,0 +1 @@ +export {default as CompleteCreateEventPage} from './CompleteCreateEvent'; From 367db233d479d8f496b831a74c831996ce1ea452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=84=ED=98=B8?= Date: Tue, 16 Jul 2024 01:01:38 +0900 Subject: [PATCH 026/178] =?UTF-8?q?design:=20=EC=A0=84=EC=97=AD=20?= =?UTF-8?q?=EC=8A=A4=ED=83=80=EC=9D=BC=EB=A7=81=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe --- client/src/index.css | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 client/src/index.css diff --git a/client/src/index.css b/client/src/index.css new file mode 100644 index 000000000..c6eed01ac --- /dev/null +++ b/client/src/index.css @@ -0,0 +1,5 @@ +body { + max-width: 768px; + margin: 0 auto; + border: 1px solid gray; +} From 6b2c45a041967355289baa35ab483a67d7b28fab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=84=ED=98=B8?= Date: Tue, 16 Jul 2024 01:02:42 +0900 Subject: [PATCH 027/178] =?UTF-8?q?feat:=20=EB=9D=BC=EC=9A=B0=ED=84=B0=20?= =?UTF-8?q?=EC=85=8B=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe --- client/src/router.tsx | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 client/src/router.tsx diff --git a/client/src/router.tsx b/client/src/router.tsx new file mode 100644 index 000000000..079abd426 --- /dev/null +++ b/client/src/router.tsx @@ -0,0 +1,35 @@ +import {createBrowserRouter} from 'react-router-dom'; +import App from './App'; +import {ROUTER_URLS} from './constants/routerUrls'; +import {MainPage} from './pages/Main'; +import {CreateEventPage} from './pages/CreateEvent'; +import {CompleteCreateEventPage} from './pages/CompleteCreateEvent'; +import {EventPage} from './pages/Event'; + +const router = createBrowserRouter([ + { + path: '', + element: , + children: [ + { + index: true, + path: ROUTER_URLS.main, + element: , + }, + { + path: ROUTER_URLS.createEvent, + element: , + }, + { + path: ROUTER_URLS.completeCreateEvent, + element: , + }, + { + path: ROUTER_URLS.eventManage, + element: , + }, + ], + }, +]); + +export default router; From fb6b0944d1d6aedaf1a925408d9be88e28e6580a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=84=ED=98=B8?= Date: Tue, 16 Jul 2024 01:03:03 +0900 Subject: [PATCH 028/178] =?UTF-8?q?feat:=20=EC=95=B1=EC=9D=98=20=EC=A7=84?= =?UTF-8?q?=EC=9E=85=EC=A0=90=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe --- client/src/App.tsx | 10 ++-------- client/src/index.tsx | 11 +++++++---- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/client/src/App.tsx b/client/src/App.tsx index 5a7e5f458..b6c73d8be 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,13 +1,7 @@ -import {css} from '@emotion/react'; -// co-authored-by test - -// 테스트 css props 사용 예제입니다. 추후 삭제 예정 -const style = css` - color: red; -`; +import {Outlet} from 'react-router-dom'; const App: React.FC = () => { - return
Hello, React with Webpack
; + return ; }; export default App; diff --git a/client/src/index.tsx b/client/src/index.tsx index e3791f790..a9cac3df9 100644 --- a/client/src/index.tsx +++ b/client/src/index.tsx @@ -1,9 +1,12 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; -import App from './App'; +import {RouterProvider} from 'react-router-dom'; +import router from './router'; +import './reset.css'; +import './index.css'; ReactDOM.createRoot(document.getElementById('root')!).render( - - - , + + + , ); From e102d59d34482f5e07e38b311078e4a14e2b293c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=84=ED=98=B8?= Date: Tue, 16 Jul 2024 01:03:49 +0900 Subject: [PATCH 029/178] =?UTF-8?q?feat:=20=EB=9D=BC=EC=9A=B0=ED=8A=B8=20?= =?UTF-8?q?=EA=B2=BD=EB=A1=9C=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe --- client/src/constants/routerUrls.ts | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 client/src/constants/routerUrls.ts diff --git a/client/src/constants/routerUrls.ts b/client/src/constants/routerUrls.ts new file mode 100644 index 000000000..c93f9fefe --- /dev/null +++ b/client/src/constants/routerUrls.ts @@ -0,0 +1,7 @@ +export const ROUTER_URLS = { + main: '', + createEvent: '/create-event', + completeCreateEvent: '/create-event/complete', + event: '/event', + eventManage: '/event/:eventId', +}; From 3d4a4b98c8747f4b6f1f6723e3c69b5de41de311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=84=ED=98=B8?= Date: Tue, 16 Jul 2024 03:28:17 +0900 Subject: [PATCH 030/178] =?UTF-8?q?fix:=20=EB=9D=BC=EC=9A=B0=ED=8A=B8=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=20=EC=8B=9C=20=ED=8E=98=EC=9D=B4=EC=A7=80?= =?UTF-8?q?=EA=B0=80=20=EC=A0=9C=EB=8C=80=EB=A1=9C=20=EB=B3=B4=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8D=98=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe --- client/webpack.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/client/webpack.config.js b/client/webpack.config.js index b002366f3..1c48c4260 100644 --- a/client/webpack.config.js +++ b/client/webpack.config.js @@ -16,6 +16,7 @@ export default { output: { path: path.join(__dirname, 'dist'), filename: 'bundle.min.js', + publicPath: '/', }, module: { rules: [ From 74378e6d8712318e64060fd7150ae20ad86215b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=84=ED=98=B8?= Date: Tue, 16 Jul 2024 03:29:13 +0900 Subject: [PATCH 031/178] =?UTF-8?q?feat:=20=EB=AA=A8=EB=8B=AC=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe --- client/src/components/Modal/Modal.style.ts | 23 ++++++++++++++++++++++ client/src/components/Modal/Modal.tsx | 19 ++++++++++++++++++ client/src/components/Modal/index.ts | 1 + 3 files changed, 43 insertions(+) create mode 100644 client/src/components/Modal/Modal.style.ts create mode 100644 client/src/components/Modal/Modal.tsx create mode 100644 client/src/components/Modal/index.ts diff --git a/client/src/components/Modal/Modal.style.ts b/client/src/components/Modal/Modal.style.ts new file mode 100644 index 000000000..727d0482f --- /dev/null +++ b/client/src/components/Modal/Modal.style.ts @@ -0,0 +1,23 @@ +import {css} from '@emotion/react'; + +export const modalBodyStyle = css` + z-index: 100; + background-color: white; + position: fixed; + bottom: 0; + left: 0; + right: 0; + padding: 20px; + border-radius: 20px 20px 0 0; + box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1); +`; + +export const modalBackdropStyle = css` + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.5); + z-index: 99; +`; diff --git a/client/src/components/Modal/Modal.tsx b/client/src/components/Modal/Modal.tsx new file mode 100644 index 000000000..323262a2e --- /dev/null +++ b/client/src/components/Modal/Modal.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import {css} from '@emotion/react'; +import {modalBodyStyle, modalBackdropStyle} from './Modal.style'; + +interface ModalProps { + children: React.ReactNode; + onClose: () => void; +} + +const Modal = ({children, onClose}: ModalProps) => { + return ( + <> +
+
{children}
+ + ); +}; + +export default Modal; diff --git a/client/src/components/Modal/index.ts b/client/src/components/Modal/index.ts new file mode 100644 index 000000000..1693a3eef --- /dev/null +++ b/client/src/components/Modal/index.ts @@ -0,0 +1 @@ +export {default as Modal} from './Modal'; From c3e7e64e0f5bdd399a916bfffe852fb44a3546d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=84=ED=98=B8?= Date: Tue, 16 Jul 2024 03:29:32 +0900 Subject: [PATCH 032/178] =?UTF-8?q?feat:=20=EC=8A=A4=EC=9C=84=EC=B9=98=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe --- client/src/components/Switch/Switch.style.tsx | 17 ++++++++++++ client/src/components/Switch/Switch.tsx | 27 +++++++++++++++++++ client/src/components/Switch/index.tsx | 1 + 3 files changed, 45 insertions(+) create mode 100644 client/src/components/Switch/Switch.style.tsx create mode 100644 client/src/components/Switch/Switch.tsx create mode 100644 client/src/components/Switch/index.tsx diff --git a/client/src/components/Switch/Switch.style.tsx b/client/src/components/Switch/Switch.style.tsx new file mode 100644 index 000000000..0e1b81b50 --- /dev/null +++ b/client/src/components/Switch/Switch.style.tsx @@ -0,0 +1,17 @@ +import {css} from '@emotion/react'; + +export const buttonStyle = (isActive: boolean) => css` + font-weight: ${isActive ? 'bold' : 'normal'}; + color: ${isActive ? '#333' : '#ccc'}; + padding: 10px; + cursor: pointer; +`; + +export const dividerStyle = css` + color: #ccc; +`; + +export const switchStyle = css` + display: flex; + align-items: center; +`; diff --git a/client/src/components/Switch/Switch.tsx b/client/src/components/Switch/Switch.tsx new file mode 100644 index 000000000..8fca98b73 --- /dev/null +++ b/client/src/components/Switch/Switch.tsx @@ -0,0 +1,27 @@ +import {buttonStyle, switchStyle} from './Switch.style'; +import React from 'react'; + +interface SwitchProps { + buttonList: string[]; + initialButton?: string; + curSwitch: string; + setSwitch: React.Dispatch>; +} + +const Switch = ({buttonList, initialButton = buttonList[0], setSwitch, curSwitch}: SwitchProps) => { + const handleButtonClick = (type: string) => { + setSwitch(type); + }; + + return ( +
+ {buttonList.map(buttonName => ( + + ))} +
+ ); +}; + +export default Switch; diff --git a/client/src/components/Switch/index.tsx b/client/src/components/Switch/index.tsx new file mode 100644 index 000000000..6c9915003 --- /dev/null +++ b/client/src/components/Switch/index.tsx @@ -0,0 +1 @@ +export {default as Switch} from './Switch'; From af02b4ee3d687817be4d4eab63438e2bff7db04c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=84=ED=98=B8?= Date: Tue, 16 Jul 2024 03:30:32 +0900 Subject: [PATCH 033/178] =?UTF-8?q?feat:=20=EC=B4=88=EA=B8=B0=EC=9D=B8?= =?UTF-8?q?=EC=9B=90=20=EC=84=B8=ED=8C=85=20=EA=B8=B0=EB=8A=A5=20=ED=8D=BC?= =?UTF-8?q?=EB=B8=94=EB=A6=AC=EC=8B=B1=20=EB=B0=8F=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe --- .../SetInitialParticipants.style.ts | 35 ++++++++++++++ .../SetInitialParticipants.tsx | 47 +++++++++++++++++++ .../Modal/SetInitialParticipants/index.ts | 1 + 3 files changed, 83 insertions(+) create mode 100644 client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.style.ts create mode 100644 client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.tsx create mode 100644 client/src/components/Modal/SetInitialParticipants/index.ts diff --git a/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.style.ts b/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.style.ts new file mode 100644 index 000000000..7f666c8d1 --- /dev/null +++ b/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.style.ts @@ -0,0 +1,35 @@ +import {css} from '@emotion/react'; + +export const inputStyle = css` + width: 100%; + padding: 10px; + border: 1px solid #ccc; + border-radius: 10px; + margin-bottom: 10px; +`; + +export const buttonStyle = (isActive: boolean) => css` + display: block; + width: 100%; + padding: 10px; + background-color: ${isActive ? '#B575FF' : '#e0e0e0'}; + border: none; + border-radius: 10px; + text-align: center; + color: ${isActive ? 'white' : '#999'}; + margin-top: 10px; +`; + +export const plusButtonStyle = css` + display: flex; + justify-content: center; + align-items: center; + width: 40px; + height: 40px; + background-color: #f5f5ff; + border: none; + border-radius: 50%; + color: #9e77ed; + font-size: 24px; + margin: 20px auto; +`; diff --git a/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.tsx b/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.tsx new file mode 100644 index 000000000..115e4c576 --- /dev/null +++ b/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.tsx @@ -0,0 +1,47 @@ +import {useState} from 'react'; +import {buttonStyle, inputStyle, plusButtonStyle} from './SetInitialParticipants.style'; + +interface SetInitialParticipantsProps { + setParticipantsAndModalClose: (participants: string[]) => void; +} + +const SetInitialParticipants = ({setParticipantsAndModalClose}: SetInitialParticipantsProps) => { + const [value, setValue] = useState(''); + const [participants, setParticipants] = useState([]); + + const addParticipants = (event: React.FormEvent) => { + if (value === '') return; + + event.preventDefault(); + setParticipants(prev => [...prev, value]); + setValue(''); + }; + + return ( + <> +

초기 인원 설정하기

+ {participants.map((participant, index) => ( + + ))} +
+ setValue(event.target.value)} + /> + +
+ + + ); +}; + +export default SetInitialParticipants; diff --git a/client/src/components/Modal/SetInitialParticipants/index.ts b/client/src/components/Modal/SetInitialParticipants/index.ts new file mode 100644 index 000000000..c41b6a206 --- /dev/null +++ b/client/src/components/Modal/SetInitialParticipants/index.ts @@ -0,0 +1 @@ +export {default as SetInitialParticipants} from './SetInitialParticipants'; From 64192d02254e1b804be42c9d77b9046e0a797ab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=84=ED=98=B8?= Date: Tue, 16 Jul 2024 03:32:48 +0900 Subject: [PATCH 034/178] =?UTF-8?q?feat:=20=ED=96=89=EB=8F=99=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=EB=A5=BC=20=EC=9C=84=ED=95=9C=20=EB=AA=A8=EB=8B=AC=20?= =?UTF-8?q?=EC=BB=A8=ED=85=90=EC=B8=A0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe --- .../SetActionModalContent.style.tsx | 24 +++++++++ .../SetActionModalContent.tsx | 52 +++++++++++++++++++ .../Modal/SetActionModalContent/index.ts | 1 + 3 files changed, 77 insertions(+) create mode 100644 client/src/components/Modal/SetActionModalContent/SetActionModalContent.style.tsx create mode 100644 client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx create mode 100644 client/src/components/Modal/SetActionModalContent/index.ts diff --git a/client/src/components/Modal/SetActionModalContent/SetActionModalContent.style.tsx b/client/src/components/Modal/SetActionModalContent/SetActionModalContent.style.tsx new file mode 100644 index 000000000..48e975e9c --- /dev/null +++ b/client/src/components/Modal/SetActionModalContent/SetActionModalContent.style.tsx @@ -0,0 +1,24 @@ +import {css} from '@emotion/react'; + +export const buttonStyle = (isActive: boolean) => css` + font-weight: ${isActive ? 'bold' : 'normal'}; + color: ${isActive ? '#333' : '#ccc'}; + padding: 10px; + cursor: pointer; +`; + +export const dividerStyle = css` + margin: 0 10px; + color: #ccc; +`; + +export const switchStyle = css` + display: flex; + align-items: center; +`; + +export const switchContainerStyle = css` + display: flex; + width: 100%; + justify-content: space-between; +`; diff --git a/client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx b/client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx new file mode 100644 index 000000000..2fca07526 --- /dev/null +++ b/client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx @@ -0,0 +1,52 @@ +import {PurchaseInformation} from '../../../pages/Event/Event'; +import {Switch} from '../../../components/Switch'; +import SetPurchase from './SetPurchase'; +import {useState} from 'react'; +import UpdateParticipants from './UpdateParticipants'; +import {switchContainerStyle} from './SetActionModalContent.style'; + +// type ActionType = '지출' | '인원'; + +interface SetActionModalContentProps { + setOpen: React.Dispatch>; + participants: string[]; + setParticipants: React.Dispatch>; + purchaseInformation: PurchaseInformation; + setPurchaseInformation: React.Dispatch>; +} + +const SetActionModalContent = ({ + setOpen, + participants, + setParticipants, + purchaseInformation, + setPurchaseInformation, +}: SetActionModalContentProps) => { + const [actionType, setActionType] = useState('지출'); + const [participantType, setParticipantType] = useState('늦참'); + + return ( + <> +
+ + {actionType === '인원' && ( + + )} +
+ + {actionType === '지출' && ( + + )} + {actionType === '인원' && ( + + )} + + ); +}; + +export default SetActionModalContent; diff --git a/client/src/components/Modal/SetActionModalContent/index.ts b/client/src/components/Modal/SetActionModalContent/index.ts new file mode 100644 index 000000000..c7514135c --- /dev/null +++ b/client/src/components/Modal/SetActionModalContent/index.ts @@ -0,0 +1 @@ +export {default as SetActionModalContent} from './SetActionModalContent'; From 5ebfab3262a5d43b11a19a0e19a67397c1f4afbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=84=ED=98=B8?= Date: Tue, 16 Jul 2024 03:34:51 +0900 Subject: [PATCH 035/178] =?UTF-8?q?feat:=20=EC=A7=80=EC=B6=9C=20=EB=82=B4?= =?UTF-8?q?=EC=97=AD=20=EA=B4=80=EB=A6=AC=20=EA=B8=B0=EB=8A=A5=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe --- .../SetActionModalContent/SetPurchase.tsx | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 client/src/components/Modal/SetActionModalContent/SetPurchase.tsx diff --git a/client/src/components/Modal/SetActionModalContent/SetPurchase.tsx b/client/src/components/Modal/SetActionModalContent/SetPurchase.tsx new file mode 100644 index 000000000..8506c2813 --- /dev/null +++ b/client/src/components/Modal/SetActionModalContent/SetPurchase.tsx @@ -0,0 +1,28 @@ +import {PurchaseInformation} from '../../../pages/Event/Event'; + +interface SetPurchaseProps { + setPurchaseInformation: (info: PurchaseInformation) => void; + purchaseInformation: PurchaseInformation; +} + +const SetPurchase = ({setPurchaseInformation, purchaseInformation}: SetPurchaseProps) => { + const handleNameChange = (e: React.ChangeEvent) => { + setPurchaseInformation({...purchaseInformation, name: e.target.value}); + }; + + const handlePriceChange = (e: React.ChangeEvent) => { + setPurchaseInformation({...purchaseInformation, price: parseFloat(e.target.value)}); + }; + + return ( + <> +
+ + +
+ + + ); +}; + +export default SetPurchase; From 077c88b89fb0494dd84db6d8a1e43e8525acd0df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=84=ED=98=B8?= Date: Tue, 16 Jul 2024 03:35:04 +0900 Subject: [PATCH 036/178] =?UTF-8?q?feat:=20=EC=9D=B8=EC=9B=90=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=EA=B8=B0=EB=8A=A5=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe --- .../UpdateParticipants.tsx | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 client/src/components/Modal/SetActionModalContent/UpdateParticipants.tsx diff --git a/client/src/components/Modal/SetActionModalContent/UpdateParticipants.tsx b/client/src/components/Modal/SetActionModalContent/UpdateParticipants.tsx new file mode 100644 index 000000000..0ec844f56 --- /dev/null +++ b/client/src/components/Modal/SetActionModalContent/UpdateParticipants.tsx @@ -0,0 +1,42 @@ +import {useState} from 'react'; + +interface UpdateParticipantsProps { + setOpen: React.Dispatch>; + participantType: string; + participants: string[]; + setParticipants: React.Dispatch>; +} + +const UpdateParticipants = ({setOpen, participantType, participants, setParticipants}: UpdateParticipantsProps) => { + const [name, setName] = useState(''); + + const updateParticipant = () => { + if (participantType === '늦참') { + if (participants.includes(name)) { + alert('이미 있는 사용자입니다.'); + return; + } + + setParticipants([...participants, name]); + } else if (participantType === '탈주') { + if (!participants.includes(name)) { + alert('그런 사용자는 없습니다. 올바른 이름을 입력해주세요.'); + return; + } + + setParticipants(prev => prev.filter(participant => participant !== name)); + } + + setName(''); + setOpen(false); + }; + + return ( +
+ setName(event.target.value)} value={name} /> + +
+ ); +}; + +export default UpdateParticipants; From 82b874386ab35eb36dfde18a671c1fb4a815f22f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=84=ED=98=B8?= Date: Tue, 16 Jul 2024 03:35:25 +0900 Subject: [PATCH 037/178] =?UTF-8?q?feat:=20=ED=96=89=EC=82=AC=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=ED=8D=BC=EB=B8=94?= =?UTF-8?q?=EB=A6=AC=EC=8B=B1=20=EB=B0=8F=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe --- client/src/pages/Event/Event.style.ts | 17 +++++++ client/src/pages/Event/Event.tsx | 72 +++++++++++++++++++++++++++ client/src/pages/Event/index.ts | 1 + 3 files changed, 90 insertions(+) create mode 100644 client/src/pages/Event/Event.style.ts create mode 100644 client/src/pages/Event/Event.tsx create mode 100644 client/src/pages/Event/index.ts diff --git a/client/src/pages/Event/Event.style.ts b/client/src/pages/Event/Event.style.ts new file mode 100644 index 000000000..517466c92 --- /dev/null +++ b/client/src/pages/Event/Event.style.ts @@ -0,0 +1,17 @@ +import {css} from '@emotion/react'; + +export const orderHeaderStyle = css` + display: flex; + justify-content: space-between; + align-items: center; + + width: 100%; +`; + +export const orderFooterStyle = css` + display: flex; + justify-content: space-between; + align-items: center; + + width: 100%; +`; diff --git a/client/src/pages/Event/Event.tsx b/client/src/pages/Event/Event.tsx new file mode 100644 index 000000000..4f311809d --- /dev/null +++ b/client/src/pages/Event/Event.tsx @@ -0,0 +1,72 @@ +import {SetInitialParticipants} from '../../components/Modal/SetInitialParticipants'; +import {Modal} from '../../components/Modal'; +import {useState} from 'react'; +import {useParams} from 'react-router-dom'; +import {SetActionModalContent} from '../../components/Modal/SetActionModalContent'; +import {orderFooterStyle, orderHeaderStyle} from './Event.style'; + +export type PurchaseInformation = { + name: string; + price: number; +}; + +const Event = () => { + const {eventId} = useParams(); + const [open, setOpen] = useState(false); + const [participants, setParticipants] = useState([]); + const [order, setOrder] = useState(0); + + const [purchaseInformation, setPurchaseInformation] = useState({ + name: '', + price: 0, + }); + + const setParticipantsAndModalClose = (participants: string[]) => { + setParticipants(participants); + setOrder(1); + setOpen(false); + }; + + return ( +
+

{eventId}

+

“초기인원 설정하기” 버튼을 눌러서 행사 초기 인원을 설정해 주세요.

+ {order > 0 && ( +
+
+

{`${order}차`}

+

{`${participants.length}명`}

+
+
+
{purchaseInformation.name}
+

{purchaseInformation.price.toLocaleString()}

+
+
+
총액
+

{purchaseInformation.price.toLocaleString()}

+
+
+ )} + + {open && ( + setOpen(false)}> + {participants.length === 0 ? ( + + ) : ( + + )} + + )} +
+ ); +}; + +export default Event; diff --git a/client/src/pages/Event/index.ts b/client/src/pages/Event/index.ts new file mode 100644 index 000000000..fa85db27a --- /dev/null +++ b/client/src/pages/Event/index.ts @@ -0,0 +1 @@ +export {default as EventPage} from './Event'; From e8adc5b00d311cc70ae3309ace3ec1e7a42d94a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=84=ED=98=B8?= Date: Wed, 17 Jul 2024 15:44:03 +0900 Subject: [PATCH 038/178] =?UTF-8?q?feat:=20=ED=95=B4=EC=BB=A4=ED=86=A4=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=20=EC=B6=9C=EB=A0=A5=EC=9D=84=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20=EC=9E=84=EC=8B=9C=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pakxe --- .../SetActionModalContent.tsx | 12 ++++-- .../SetActionModalContent/SetPurchase.tsx | 30 ++++++++++---- .../UpdateParticipants.tsx | 13 +++++- client/src/pages/Event/Event.tsx | 41 ++++++++++++++----- 4 files changed, 73 insertions(+), 23 deletions(-) diff --git a/client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx b/client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx index 2fca07526..931dc523d 100644 --- a/client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx +++ b/client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx @@ -11,8 +11,8 @@ interface SetActionModalContentProps { setOpen: React.Dispatch>; participants: string[]; setParticipants: React.Dispatch>; - purchaseInformation: PurchaseInformation; - setPurchaseInformation: React.Dispatch>; + purchaseInformation: any; + setPurchaseInformation: any; } const SetActionModalContent = ({ @@ -35,7 +35,11 @@ const SetActionModalContent = ({
{actionType === '지출' && ( - + )} {actionType === '인원' && ( )} diff --git a/client/src/components/Modal/SetActionModalContent/SetPurchase.tsx b/client/src/components/Modal/SetActionModalContent/SetPurchase.tsx index 8506c2813..b40176c78 100644 --- a/client/src/components/Modal/SetActionModalContent/SetPurchase.tsx +++ b/client/src/components/Modal/SetActionModalContent/SetPurchase.tsx @@ -1,26 +1,40 @@ +import {useState} from 'react'; import {PurchaseInformation} from '../../../pages/Event/Event'; interface SetPurchaseProps { - setPurchaseInformation: (info: PurchaseInformation) => void; - purchaseInformation: PurchaseInformation; + setOpen: React.Dispatch>; + setPurchaseInformation: any; + purchaseInformation: any; } -const SetPurchase = ({setPurchaseInformation, purchaseInformation}: SetPurchaseProps) => { +const SetPurchase = ({setOpen, setPurchaseInformation}: SetPurchaseProps) => { + const [newPurchaseInformation, setNewPurchaseInformation] = useState({ + name: '', + price: 0, + }); + const handleNameChange = (e: React.ChangeEvent) => { - setPurchaseInformation({...purchaseInformation, name: e.target.value}); + setNewPurchaseInformation({...newPurchaseInformation, name: e.target.value}); }; const handlePriceChange = (e: React.ChangeEvent) => { - setPurchaseInformation({...purchaseInformation, price: parseFloat(e.target.value)}); + setNewPurchaseInformation({...newPurchaseInformation, price: parseFloat(e.target.value)}); + }; + + const addPurchaseInformation = () => { + setPurchaseInformation((prev: PurchaseInformation[]) => [...prev, newPurchaseInformation]); + setOpen(false); }; return ( <>
- - + +
- + ); }; diff --git a/client/src/components/Modal/SetActionModalContent/UpdateParticipants.tsx b/client/src/components/Modal/SetActionModalContent/UpdateParticipants.tsx index 0ec844f56..e64ceff53 100644 --- a/client/src/components/Modal/SetActionModalContent/UpdateParticipants.tsx +++ b/client/src/components/Modal/SetActionModalContent/UpdateParticipants.tsx @@ -5,9 +5,18 @@ interface UpdateParticipantsProps { participantType: string; participants: string[]; setParticipants: React.Dispatch>; + setPurchaseInformation: any; + purchaseInformation: any; } -const UpdateParticipants = ({setOpen, participantType, participants, setParticipants}: UpdateParticipantsProps) => { +const UpdateParticipants = ({ + setPurchaseInformation, + purchaseInformation, + setOpen, + participantType, + participants, + setParticipants, +}: UpdateParticipantsProps) => { const [name, setName] = useState(''); const updateParticipant = () => { @@ -18,6 +27,7 @@ const UpdateParticipants = ({setOpen, participantType, participants, setParticip } setParticipants([...participants, name]); + setPurchaseInformation([...purchaseInformation, {name, type: '늦참'}]); } else if (participantType === '탈주') { if (!participants.includes(name)) { alert('그런 사용자는 없습니다. 올바른 이름을 입력해주세요.'); @@ -25,6 +35,7 @@ const UpdateParticipants = ({setOpen, participantType, participants, setParticip } setParticipants(prev => prev.filter(participant => participant !== name)); + setPurchaseInformation([...purchaseInformation, {name, type: '탈주'}]); } setName(''); diff --git a/client/src/pages/Event/Event.tsx b/client/src/pages/Event/Event.tsx index 4f311809d..c7cb2d245 100644 --- a/client/src/pages/Event/Event.tsx +++ b/client/src/pages/Event/Event.tsx @@ -10,16 +10,23 @@ export type PurchaseInformation = { price: number; }; +type ParticipantType = { + name: string; + type: '늦참' | '탈주'; +}; + const Event = () => { const {eventId} = useParams(); const [open, setOpen] = useState(false); const [participants, setParticipants] = useState([]); const [order, setOrder] = useState(0); - const [purchaseInformation, setPurchaseInformation] = useState({ - name: '', - price: 0, - }); + const [purchaseInformation, setPurchaseInformation] = useState<(PurchaseInformation | ParticipantType)[]>([ + { + name: '', + price: 0, + } as PurchaseInformation, + ]); const setParticipantsAndModalClose = (participants: string[]) => { setParticipants(participants); @@ -37,14 +44,26 @@ const Event = () => {

{`${order}차`}

{`${participants.length}명`}

-
-
{purchaseInformation.name}
-

{purchaseInformation.price.toLocaleString()}

-
-
+ {purchaseInformation.map((information, index) => ( +
+ {'type' in information ? ( + <> +
+ {information.name} {information.type}입니다. +
+ + ) : ( + <> +
{information.name}
+

{information.price.toLocaleString()}원

+ + )} +
+ ))} + {/*
총액
-

{purchaseInformation.price.toLocaleString()}

-
+

{purchaseInformation.reduce((total, info) => 'price' in info ? total + info.price : total, 0).toLocaleString()}원

+
*/} )} + ); +}); + +export default IconButton; diff --git a/HDesign/src/components/IconButton/IconButton.type.ts b/HDesign/src/components/IconButton/IconButton.type.ts new file mode 100644 index 000000000..10415621c --- /dev/null +++ b/HDesign/src/components/IconButton/IconButton.type.ts @@ -0,0 +1,11 @@ +type IconButtonType = 'inputDelete' | 'plus' | 'buljusa'; + +export interface IconButtonStyleProps {} + +export interface IconButtonCustomProps { + iconType: IconButtonType; +} + +export type IconButtonOptionProps = IconButtonStyleProps & IconButtonCustomProps; + +export type IconButtonProps = React.ComponentProps<'button'> & IconButtonOptionProps; diff --git a/HDesign/src/components/InOutItem/InOutItem.stories.tsx b/HDesign/src/components/InOutItem/InOutItem.stories.tsx new file mode 100644 index 000000000..595e22b12 --- /dev/null +++ b/HDesign/src/components/InOutItem/InOutItem.stories.tsx @@ -0,0 +1,32 @@ +import type {Meta, StoryObj} from '@storybook/react'; + +import InOutItem from '@components/InOutItem/InOutItem'; + +const meta = { + title: 'Components/InOutItem', + component: InOutItem, + tags: ['autodocs'], + parameters: { + // layout: 'centered', + }, + argTypes: { + names: { + description: '', + control: {type: 'text'}, + }, + inOutType: { + description: '', + control: {type: 'select', options: ['in', 'out']}, + }, + }, + args: { + names: ['감자', '토다리'], + inOutType: 'out', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/InOutItem/InOutItem.style.ts b/HDesign/src/components/InOutItem/InOutItem.style.ts new file mode 100644 index 000000000..b14dedae8 --- /dev/null +++ b/HDesign/src/components/InOutItem/InOutItem.style.ts @@ -0,0 +1,21 @@ +import {Theme} from '@/theme/theme.type'; +import {css} from '@emotion/react'; + +export const inOutItemStyle = (theme: Theme) => + css({ + display: 'flex', + justifyContent: 'space-between', + padding: '0.5rem 0.5rem 0.5rem 0.25rem', + borderRadius: '0.5rem', + backgroundColor: theme.colors.white, + }); + +export const prefixStyle = css({ + display: 'flex', + gap: '0.25rem', +}); + +export const textStyle = (theme: Theme) => + css({ + color: theme.colors.black, + }); diff --git a/HDesign/src/components/InOutItem/InOutItem.tsx b/HDesign/src/components/InOutItem/InOutItem.tsx new file mode 100644 index 000000000..97548cd40 --- /dev/null +++ b/HDesign/src/components/InOutItem/InOutItem.tsx @@ -0,0 +1,26 @@ +/** @jsxImportSource @emotion/react */ +import React from 'react'; + +import {useTheme} from '@theme/HDesignProvider'; + +import {InOutItemProps} from './InOutItem.type'; +import {inOutItemStyle, prefixStyle, textStyle} from './InOutItem.style'; +import Text from '@components/Text/Text'; +import IconButton from '../IconButton/IconButton'; + +export const InOutItem: React.FC = ({names = [], inOutType = 'out', ...htmlProps}: InOutItemProps) => { + const {theme} = useTheme(); + + // TODO: (@toari) : 사람 수 많을 때 UX writing 처리 + return ( +
+
+ + + {names.join(', ')} {inOutType === 'out' ? '나감' : '들어옴'} + +
+
+ ); +}; +export default InOutItem; diff --git a/HDesign/src/components/InOutItem/InOutItem.type.ts b/HDesign/src/components/InOutItem/InOutItem.type.ts new file mode 100644 index 000000000..c82fad4f8 --- /dev/null +++ b/HDesign/src/components/InOutItem/InOutItem.type.ts @@ -0,0 +1,12 @@ +export type InOutType = 'in' | 'out'; + +export interface InOutItemStyleProps {} + +export interface InOutItemCustomProps { + names?: string[]; + inOutType?: InOutType; +} + +export type InOutItemOptionProps = InOutItemStyleProps & InOutItemCustomProps; + +export type InOutItemProps = React.ComponentProps<'div'> & InOutItemOptionProps; diff --git a/HDesign/src/components/Input/Input.stories.tsx b/HDesign/src/components/Input/Input.stories.tsx new file mode 100644 index 000000000..da5df07ab --- /dev/null +++ b/HDesign/src/components/Input/Input.stories.tsx @@ -0,0 +1,28 @@ +import type {Meta, StoryObj} from '@storybook/react'; + +import Input from '@components/Input/Input'; + +const meta = { + title: 'Components/Input', + component: Input, + tags: ['autodocs'], + parameters: { + // layout: 'centered', + }, + argTypes: { + value: { + description: '', + control: {type: 'text'}, + }, + }, + args: { + disabled: false, + placeholder: 'placeholder', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/Input/Input.style.ts b/HDesign/src/components/Input/Input.style.ts new file mode 100644 index 000000000..b23ba358c --- /dev/null +++ b/HDesign/src/components/Input/Input.style.ts @@ -0,0 +1,27 @@ +import {css} from '@emotion/react'; + +import {Theme} from '@theme/theme.type'; + +export const inputBoxStyle = (theme: Theme) => + css({ + display: 'flex', + width: '100%', + justifyContent: 'space-between', + padding: '0.75rem 1rem', + borderRadius: '1rem', + backgroundColor: theme.colors.grayContainer, + }); + +export const inputStyle = (theme: Theme) => + css( + { + display: 'flex', + width: '100%', + color: theme.colors.black, + + '&:placeholder': { + color: theme.colors.gray, + }, + }, + theme.typography.body, + ); diff --git a/HDesign/src/components/Input/Input.tsx b/HDesign/src/components/Input/Input.tsx new file mode 100644 index 000000000..8f6c35e1e --- /dev/null +++ b/HDesign/src/components/Input/Input.tsx @@ -0,0 +1,30 @@ +/** @jsxImportSource @emotion/react */ +import React, {forwardRef, useImperativeHandle, useRef} from 'react'; + +import IconButton from '@components/IconButton/IconButton'; +import {InputProps} from '@components/Input/Input.type'; +import {inputBoxStyle, inputStyle} from '@components/Input/Input.style'; +import {useInput} from '@components/Input/useInput'; + +import {useTheme} from '@theme/HDesignProvider'; + +export const Input: React.FC = forwardRef(function Input( + {value: propsValue, onChange, ...htmlProps}: InputProps, + ref, +) { + const {theme} = useTheme(); + const inputRef = useRef(null); + + useImperativeHandle(ref, () => inputRef.current!); + + const {value, handleChange, handleClickDelete} = useInput({propsValue, onChange, inputRef}); + + return ( +
+ + {value && } +
+ ); +}); + +export default Input; diff --git a/HDesign/src/components/Input/Input.type.ts b/HDesign/src/components/Input/Input.type.ts new file mode 100644 index 000000000..da35ca5ed --- /dev/null +++ b/HDesign/src/components/Input/Input.type.ts @@ -0,0 +1,11 @@ +import {Theme} from '@theme/theme.type'; + +export interface InputStyleProps { + theme?: Theme; +} + +export interface InputCustomProps {} + +export type InputOptionProps = InputStyleProps & InputCustomProps; + +export type InputProps = React.ComponentProps<'input'> & InputOptionProps; diff --git a/HDesign/src/components/Input/useInput.ts b/HDesign/src/components/Input/useInput.ts new file mode 100644 index 000000000..af4892964 --- /dev/null +++ b/HDesign/src/components/Input/useInput.ts @@ -0,0 +1,36 @@ +import {RefObject, useEffect, useState} from 'react'; + +interface UseInputProps { + propsValue: T; + onChange?: (e: React.ChangeEvent) => void; + inputRef: RefObject; +} + +export const useInput = ({propsValue, onChange, inputRef}: UseInputProps) => { + const [value, setValue] = useState(propsValue || ''); + + useEffect(() => { + setValue(propsValue || ''); + }, [propsValue]); + + const handleClickDelete = () => { + setValue(''); + + if (inputRef.current) { + inputRef.current.focus(); + } + + if (onChange) { + onChange({target: {value: ''}} as React.ChangeEvent); + } + }; + + const handleChange = (e: React.ChangeEvent) => { + setValue(e.target.value); + if (onChange) { + onChange(e); + } + }; + + return {value, handleChange, handleClickDelete}; +}; diff --git a/HDesign/src/components/StepItem/StepItem.stories.tsx b/HDesign/src/components/StepItem/StepItem.stories.tsx new file mode 100644 index 000000000..3a81c38f6 --- /dev/null +++ b/HDesign/src/components/StepItem/StepItem.stories.tsx @@ -0,0 +1,46 @@ +import type {Meta, StoryObj} from '@storybook/react'; + +import StepItem from '@components/StepItem/StepItem'; + +const meta = { + title: 'Components/StepItem', + component: StepItem, + tags: ['autodocs'], + parameters: { + // layout: 'centered', + }, + argTypes: { + name: { + description: '', + control: {type: 'text'}, + }, + personCount: { + description: '', + control: {type: 'number'}, + }, + bills: { + description: '', + control: {type: 'object'}, + }, + }, + args: { + name: '으랏차차', + personCount: 8, + bills: [ + { + name: '뽕나무쟁이', + price: 150000, + }, + { + name: '인생네컷', + price: 12000, + }, + ], + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/StepItem/StepItem.style.ts b/HDesign/src/components/StepItem/StepItem.style.ts new file mode 100644 index 000000000..a82ff00e4 --- /dev/null +++ b/HDesign/src/components/StepItem/StepItem.style.ts @@ -0,0 +1,45 @@ +import {Theme} from '@/theme/theme.type'; +import {css} from '@emotion/react'; + +export const stepItemStyle = (theme: Theme) => + css({ + display: 'flex', + flexDirection: 'column', + gap: '0.5rem', + padding: '0.5rem', + borderRadius: '0.75rem', + backgroundColor: theme.colors.white, + }); + +export const headerStyle = css({ + display: 'flex', + justifyContent: 'space-between', + paddingInline: '0.5rem', +}); + +export const nameStyle = (theme: Theme) => + css({ + color: theme.colors.black, + }); + +export const personCountStyle = (theme: Theme) => + css({ + color: theme.colors.gray, + textDecoration: 'underline', + }); + +export const footerStyle = css({ + display: 'flex', + justifyContent: 'space-between', + paddingInline: '0.5rem', +}); + +export const totalTitleStyle = (theme: Theme) => + css({ + color: theme.colors.black, + }); + +export const totalAmountStyle = (theme: Theme) => + css({ + color: theme.colors.onSecondary, + }); diff --git a/HDesign/src/components/StepItem/StepItem.tsx b/HDesign/src/components/StepItem/StepItem.tsx new file mode 100644 index 000000000..43c52fa4c --- /dev/null +++ b/HDesign/src/components/StepItem/StepItem.tsx @@ -0,0 +1,48 @@ +/** @jsxImportSource @emotion/react */ +import {useTheme} from '@/theme/HDesignProvider'; +import {StepItemCustomProps} from './StepItem.type'; +import { + footerStyle, + headerStyle, + nameStyle, + personCountStyle, + stepItemStyle, + totalAmountStyle, + totalTitleStyle, +} from './StepItem.style'; +import Text from '../Text/Text'; +import BillItem from '../BillItem/BillItem'; +import {BillItemCustomProps} from '../BillItem/BillItem.type'; + +export const StepItem: React.FC = ({ + name = '', + personCount = 0, + bills, + ...htmlProps +}: StepItemCustomProps) => { + const {theme} = useTheme(); + return ( +
+
+ + {name} + + + {personCount}명 + +
+ {bills.map((props: BillItemCustomProps) => ( + + ))} +
+ + 총액 + + + {bills.reduce((acc, prev) => acc + (prev.price ?? 0), 0).toLocaleString('ko-kr')} 원 + +
+
+ ); +}; +export default StepItem; diff --git a/HDesign/src/components/StepItem/StepItem.type.ts b/HDesign/src/components/StepItem/StepItem.type.ts new file mode 100644 index 000000000..516b7b675 --- /dev/null +++ b/HDesign/src/components/StepItem/StepItem.type.ts @@ -0,0 +1,13 @@ +import {BillItemCustomProps} from '../BillItem/BillItem.type'; + +export interface StepItemStyleProps {} + +export interface StepItemCustomProps { + name: string; + personCount: number; + bills: BillItemCustomProps[]; +} + +export type StepItemOptionProps = StepItemStyleProps & StepItemCustomProps; + +export type StepItemProps = React.ComponentProps<'div'> & StepItemOptionProps; diff --git a/HDesign/lib/components/Text/Text.stories.tsx b/HDesign/src/components/Text/Text.stories.tsx similarity index 94% rename from HDesign/lib/components/Text/Text.stories.tsx rename to HDesign/src/components/Text/Text.stories.tsx index 4c3b36bf2..5e5ec2287 100644 --- a/HDesign/lib/components/Text/Text.stories.tsx +++ b/HDesign/src/components/Text/Text.stories.tsx @@ -1,6 +1,6 @@ import type {Meta, StoryObj} from '@storybook/react'; -import Text from './Text'; +import Text from '@components/Text/Text'; const meta = { title: 'Components/Text', diff --git a/HDesign/lib/components/Text/Text.style.ts b/HDesign/src/components/Text/Text.style.ts similarity index 93% rename from HDesign/lib/components/Text/Text.style.ts rename to HDesign/src/components/Text/Text.style.ts index b7ab8a2fe..356f9b0a0 100644 --- a/HDesign/lib/components/Text/Text.style.ts +++ b/HDesign/src/components/Text/Text.style.ts @@ -1,9 +1,9 @@ -import {css} from '@emotion/react'; - import type {TextProps} from './Text'; +import {css} from '@emotion/react'; + // TODO: (@todari) themeProvider 이용하도록 변경 -import TYPOGRAPHY from '../../token/typography'; +import TYPOGRAPHY from '@token/typography'; export const getSizeStyling = (size: Required['size']) => { const style = { diff --git a/HDesign/lib/components/Text/Text.tsx b/HDesign/src/components/Text/Text.tsx similarity index 73% rename from HDesign/lib/components/Text/Text.tsx rename to HDesign/src/components/Text/Text.tsx index a200648ea..f39428c8d 100644 --- a/HDesign/lib/components/Text/Text.tsx +++ b/HDesign/src/components/Text/Text.tsx @@ -1,15 +1,17 @@ /** @jsxImportSource @emotion/react */ -import React from 'react'; -import type {Size} from './Text.type'; +import type {Size} from '@components/Text/Text.type'; + import type {ComponentPropsWithoutRef} from 'react'; +import React from 'react'; + import {getSizeStyling} from './Text.style'; export interface TextProps extends ComponentPropsWithoutRef<'p'> { size?: Size | 'bodyBold' | 'smallBodyBold' | 'captionBold'; } -const Text: React.FC = ({size = 'body', children, ...attributes}: TextProps) => { +const Text: React.FC = ({size = 'body', children, ...attributes}: TextProps) => { return (

{children} diff --git a/HDesign/lib/components/Text/Text.type.ts b/HDesign/src/components/Text/Text.type.ts similarity index 100% rename from HDesign/lib/components/Text/Text.type.ts rename to HDesign/src/components/Text/Text.type.ts diff --git a/HDesign/src/components/Title/Title.stories.tsx b/HDesign/src/components/Title/Title.stories.tsx new file mode 100644 index 000000000..0b650b280 --- /dev/null +++ b/HDesign/src/components/Title/Title.stories.tsx @@ -0,0 +1,32 @@ +import type {Meta, StoryObj} from '@storybook/react'; + +import Title from '@components/Title/Title'; + +const meta = { + title: 'Components/Title', + component: Title, + tags: ['autodocs'], + parameters: { + layout: 'centered', + }, + argTypes: { + title: { + description: '', + control: {type: 'text'}, + }, + description: { + description: '', + control: {type: 'text'}, + }, + }, + args: { + title: '페이지 제목이에요', + description: '이곳에는 페이지 설명이 들어가요. 페이지에 대한 설명을 자세하게 적어주면 좋아요 :)', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/Title/Title.style.ts b/HDesign/src/components/Title/Title.style.ts new file mode 100644 index 000000000..2b298d2cf --- /dev/null +++ b/HDesign/src/components/Title/Title.style.ts @@ -0,0 +1,21 @@ +import {css} from '@emotion/react'; + +import {Theme} from '@theme/theme.type'; + +export const titleContainerStyle = css({ + display: 'flex', + flexDirection: 'column', + gap: '0.5rem', + + padding: '0 1rem', +}); + +export const titleStyle = (theme: Theme) => + css({ + color: theme.colors.black, + }); + +export const descriptionStyle = (theme: Theme) => + css({ + color: theme.colors.darkGray, + }); diff --git a/HDesign/src/components/Title/Title.tsx b/HDesign/src/components/Title/Title.tsx new file mode 100644 index 000000000..556c037e4 --- /dev/null +++ b/HDesign/src/components/Title/Title.tsx @@ -0,0 +1,20 @@ +/** @jsxImportSource @emotion/react */ +import Text from '@components/Text/Text'; +import {descriptionStyle, titleContainerStyle, titleStyle} from '@components/Title/Title.style'; +import {TitleProps} from '@components/Title/Title.type'; + +import {useTheme} from '@theme/HDesignProvider'; + +export const Title: React.FC = ({title, description}: TitleProps) => { + const {theme} = useTheme(); + return ( +

+ + {title} + + {description} +
+ ); +}; + +export default Title; diff --git a/HDesign/src/components/Title/Title.type.ts b/HDesign/src/components/Title/Title.type.ts new file mode 100644 index 000000000..fa3fb4e3f --- /dev/null +++ b/HDesign/src/components/Title/Title.type.ts @@ -0,0 +1,10 @@ +export interface TitleStyleProps {} + +export interface TitleCustomProps { + title: string; + description?: string; +} + +export type TitleOptionProps = TitleStyleProps & TitleCustomProps; + +export type TitleProps = React.ComponentProps<'div'> & TitleOptionProps; diff --git a/HDesign/src/index.tsx b/HDesign/src/index.tsx new file mode 100644 index 000000000..8c010bca0 --- /dev/null +++ b/HDesign/src/index.tsx @@ -0,0 +1,26 @@ +import BillItem from '@components/BillItem/BillItem'; +import BottomSheet from '@components/BottomSheet/BottomSheet'; +import Button from '@components/Button/Button'; +import FixedButton from '@components/FixedButton/FixedButton'; +import IconButton from '@components/IconButton/IconButton'; +import InOutItem from '@components/InOutItem/InOutItem'; +import Input from '@components/Input/Input'; +import StepItem from '@components/StepItem/StepItem'; +import Text from '@components/Text/Text'; +import Title from '@components/Title/Title'; + +import {HDesignProvider} from '@theme/HDesignProvider'; + +export { + BillItem, + BottomSheet, + Button, + FixedButton, + IconButton, + InOutItem, + Input, + StepItem, + Text, + Title, + HDesignProvider, +}; diff --git a/HDesign/lib/theme/GlobalStyle.ts b/HDesign/src/theme/GlobalStyle.ts similarity index 94% rename from HDesign/lib/theme/GlobalStyle.ts rename to HDesign/src/theme/GlobalStyle.ts index 08cd8094e..cbef1c8ea 100644 --- a/HDesign/lib/theme/GlobalStyle.ts +++ b/HDesign/src/theme/GlobalStyle.ts @@ -24,6 +24,7 @@ export const GlobalStyle = css` a, button { cursor: revert; + line-height: 0; } /* Remove list styles (bullets/numbers) */ @@ -34,12 +35,6 @@ export const GlobalStyle = css` list-style: none; } - /* For images to not be able to exceed their container */ - img { - max-inline-size: 100%; - max-block-size: 100%; - } - /* Removes spacing between cells in tables */ table { border-collapse: collapse; @@ -116,6 +111,5 @@ export const GlobalStyle = css` #root { display: flex; justify-content: center; - background-color: #eeeeee; } `; diff --git a/HDesign/lib/theme/HDesignProvider.tsx b/HDesign/src/theme/HDesignProvider.tsx similarity index 82% rename from HDesign/lib/theme/HDesignProvider.tsx rename to HDesign/src/theme/HDesignProvider.tsx index d196dba2d..6c7c571a3 100644 --- a/HDesign/lib/theme/HDesignProvider.tsx +++ b/HDesign/src/theme/HDesignProvider.tsx @@ -1,9 +1,11 @@ import React, {createContext, useContext, useState, ReactNode} from 'react'; import {Global} from '@emotion/react'; -import {COLORS} from '../token/colors'; -import {TYPOGRAPHY} from '../token/typography'; -import {Theme} from './theme.type'; -import {GlobalStyle} from './GlobalStyle'; + +import {Theme} from '@theme/theme.type'; +import {GlobalStyle} from '@theme/GlobalStyle'; + +import {COLORS} from '@token/colors'; +import {TYPOGRAPHY} from '@token/typography'; interface ThemeContextProps { theme: Theme; diff --git a/HDesign/src/theme/theme.type.ts b/HDesign/src/theme/theme.type.ts new file mode 100644 index 000000000..dffd961f0 --- /dev/null +++ b/HDesign/src/theme/theme.type.ts @@ -0,0 +1,7 @@ +import {ColorTokens} from '@token/colors'; +import {TypographyTokens} from '@token/typography'; + +export interface Theme { + colors: ColorTokens; + typography: TypographyTokens; +} diff --git a/HDesign/lib/token/colors.ts b/HDesign/src/token/colors.ts similarity index 84% rename from HDesign/lib/token/colors.ts rename to HDesign/src/token/colors.ts index 668f1c272..73f7b4f7f 100644 --- a/HDesign/lib/token/colors.ts +++ b/HDesign/src/token/colors.ts @@ -33,6 +33,8 @@ export type ColorTokens = Record; // TODO: (@soha) 대괄호 사용에 대해 논의 export const COLORS: ColorTokens = { white: PRIMITIVE_COLORS.white, + gray: PRIMITIVE_COLORS.gray[400], + darkGray: PRIMITIVE_COLORS.gray[500], black: PRIMITIVE_COLORS.gray[700], primary: PRIMITIVE_COLORS.purple[300], onPrimary: PRIMITIVE_COLORS.white, @@ -40,4 +42,6 @@ export const COLORS: ColorTokens = { onSecondary: PRIMITIVE_COLORS.purple[600], tertiary: PRIMITIVE_COLORS.gray[200], onTertiary: PRIMITIVE_COLORS.gray[700], + grayContainer: PRIMITIVE_COLORS.gray[100], + lightGrayContainer: PRIMITIVE_COLORS.gray[50], }; diff --git a/HDesign/lib/token/typography.ts b/HDesign/src/token/typography.ts similarity index 100% rename from HDesign/lib/token/typography.ts rename to HDesign/src/token/typography.ts diff --git a/HDesign/tsconfig.json b/HDesign/tsconfig.json index 4f0fd007a..6cbcf91bd 100644 --- a/HDesign/tsconfig.json +++ b/HDesign/tsconfig.json @@ -1,43 +1,30 @@ { "compilerOptions": { "sourceMap": true, - "module": "ES2020", - "target": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "useDefineForClassFields": true, - "removeComments": true, + "outDir": "./dist", + "target": "ES5", "skipLibCheck": true, - - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - - "jsx": "react-jsx", + "module": "commonjs", + "moduleResolution": "node", "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true, - - // "types": ["jest"], + "declaration": true, + "declarationDir": "./dist", "esModuleInterop": true, - "strictNullChecks": true, - "strictFunctionTypes": true, - "strictBindCallApply": true, - "strictPropertyInitialization": true, - "noImplicitAny": true, - "noImplicitThis": true, - "alwaysStrict": true, - "noImplicitReturns": true, "forceConsistentCasingInFileNames": true, - "jsxImportSource": "@emotion/react", - - "baseUrl": "./", + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "jsx": "react-jsx", + "allowJs": true, + "baseUrl": ".", "paths": { - "components/*": ["lib/components/*"] + "@/*": ["src/*"], + "@components/*": ["src/components/*"], + "@token/*": ["src/token/*"], + "@theme/*": ["src/theme/*"], + "@assets/*": ["src/assets/*"] }, - "outDir": "./dist" + "jsxImportSource": "@emotion/react", + "allowSyntheticDefaultImports": true }, - "include": ["lib"] + "include": ["src"], + "exclude": ["./node_modules", "dist"] } diff --git a/HDesign/webpack.config.js b/HDesign/webpack.config.js deleted file mode 100644 index e179524bc..000000000 --- a/HDesign/webpack.config.js +++ /dev/null @@ -1,44 +0,0 @@ -import path from 'path'; -import {fileURLToPath} from 'url'; - -import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; -import {ModifySourcePlugin, ConcatOperation} from 'modify-source-webpack-plugin'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -export default { - mode: 'development', - entry: './lib/index.ts', - resolve: { - extensions: ['.js', '.jsx', '.ts', '.tsx'], - }, - output: { - path: path.join(__dirname, 'dist'), - filename: 'bundle.min.js', - }, - module: { - rules: [ - { - test: /\.tsx?$/, - loader: 'ts-loader', - exclude: /node_modules/, - }, - ], - }, - plugins: [ - new ForkTsCheckerWebpackPlugin(), - new ModifySourcePlugin({ - rules: [ - { - test: /\.tsx$/i, - operations: [new ConcatOperation('start', '/** @jsxImportSource @emotion/react */\n\n')], - }, - ], - }), - ], - devServer: { - port: 3000, - hot: true, - }, -}; From e6fe89417ffd1e6293114e5c62205eda770d7d75 Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Thu, 18 Jul 2024 15:18:52 +0900 Subject: [PATCH 045/178] =?UTF-8?q?feat:=20CI/CD=20=ED=8C=8C=EC=9D=B4?= =?UTF-8?q?=ED=94=84=EB=9D=BC=EC=9D=B8=20=EA=B5=AC=EC=B6=95=20(#42)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: ci/cd 구축 * fix: ci/cd 디폴트 경로 변경 * fix: ci/cd 디폴트 경로 변경 * fix: ci/cd 디폴트 경로 변경 * fix: ci/cd 디폴트 경로 변경 * fix: ci/cd 디폴트 경로 변경 * fix: ci/cd 디폴트 경로 변경 * feat: cicd 테스트 객체 제거 * feat: cicd 테스트 객체 제거 --- .github/workflows/backend-pull-request.yml | 34 +++++++++++ .github/workflows/backend-push.yml | 68 ++++++++++++++++++++++ server/Dockerfile | 17 ++++++ 3 files changed, 119 insertions(+) create mode 100644 .github/workflows/backend-pull-request.yml create mode 100644 .github/workflows/backend-push.yml create mode 100644 server/Dockerfile diff --git a/.github/workflows/backend-pull-request.yml b/.github/workflows/backend-pull-request.yml new file mode 100644 index 000000000..a5cfbfda7 --- /dev/null +++ b/.github/workflows/backend-pull-request.yml @@ -0,0 +1,34 @@ +name: backend-pull-request + +on: + pull_request: + branches: [ "main", "develop" ] + paths: + - 'server/**' + +jobs: + build: + runs-on: ubuntu-latest + + defaults: + run: + working-directory: ./server + + permissions: + contents: read + + steps: + - name: CheckOut + uses: actions/checkout@v4 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 + + - name: Test with Gradle Wrapper + run: ./gradlew clean build diff --git a/.github/workflows/backend-push.yml b/.github/workflows/backend-push.yml new file mode 100644 index 000000000..5a8d5f4ef --- /dev/null +++ b/.github/workflows/backend-push.yml @@ -0,0 +1,68 @@ +name: backend-push + +on: + push: + branches: [ "main", "develop" ] + paths: + - 'server/**' + +jobs: + build: + runs-on: ubuntu-latest + + defaults: + run: + shell: bash + working-directory: ./server + + permissions: + contents: read + + steps: + - name: CheckOut + uses: actions/checkout@v4 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 + + - name: Test with Gradle Wrapper + run: ./gradlew test + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Set up Docker BuildX + uses: docker/setup-buildx-action@v3 + + - name: Build and push + run: | + docker buildx build --platform linux/arm64 -t \ + ${{ secrets.DOCKER_USERNAME }}/haengdong-backend-dev --push . + + deploy: + needs: build + runs-on: self-hosted + steps: + - name: Docker remove + run: | + CONTAINER_IDS=$(sudo docker ps -qa) + if [ -n "$CONTAINER_IDS" ]; then + sudo docker rm -f $CONTAINER_IDS + else + echo "No running containers found." + fi + + - name: Docker Image pull + run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/haengdong-backend-dev + + - name: Docker run + run: sudo docker run -d -p 80:8080 --name haengdong-backend-dev haengdong/haengdong-backend-dev diff --git a/server/Dockerfile b/server/Dockerfile new file mode 100644 index 000000000..38c565c85 --- /dev/null +++ b/server/Dockerfile @@ -0,0 +1,17 @@ +FROM gradle:7.6.1-jdk17 AS build + +WORKDIR /app + +COPY . /app + +RUN gradle clean build -x test + +FROM openjdk:17-jdk-slim + +WORKDIR /app + +COPY --from=build /app/build/libs/*.jar /app/haengdong-0.0.1-SNAPSHOT.jar + +EXPOSE 8080 +ENTRYPOINT ["java"] +CMD ["-jar", "haengdong-0.0.1-SNAPSHOT.jar"] From bd1b976e605b85043a3ee279b3bc0a93259f47e0 Mon Sep 17 00:00:00 2001 From: kunsanglee Date: Thu, 18 Jul 2024 14:55:05 +0900 Subject: [PATCH 046/178] =?UTF-8?q?feat:=20=ED=96=89=EC=82=AC=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../haengdong/application/EventService.java | 25 +++++++++ .../application/request/EventAppRequest.java | 10 ++++ .../response/EventAppResponse.java | 10 ++++ .../java/server/haengdong/domain/Event.java | 5 ++ .../haengdong/domain/EventTokenProvider.java | 12 +++++ .../persistence/EventRepository.java | 9 ++++ .../presentation/EventController.java | 26 ++++++++++ .../request/EventSaveRequest.java | 10 ++++ .../application/EventServiceTest.java | 35 +++++++++++++ .../presentation/EventControllerTest.java | 51 +++++++++++++++++++ 10 files changed, 193 insertions(+) create mode 100644 server/src/main/java/server/haengdong/application/EventService.java create mode 100644 server/src/main/java/server/haengdong/application/request/EventAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/response/EventAppResponse.java create mode 100644 server/src/main/java/server/haengdong/domain/EventTokenProvider.java create mode 100644 server/src/main/java/server/haengdong/persistence/EventRepository.java create mode 100644 server/src/main/java/server/haengdong/presentation/EventController.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java create mode 100644 server/src/test/java/server/haengdong/application/EventServiceTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/EventControllerTest.java diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java new file mode 100644 index 000000000..deac413a4 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -0,0 +1,25 @@ +package server.haengdong.application; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.response.EventAppResponse; +import server.haengdong.domain.Event; +import server.haengdong.domain.EventTokenProvider; +import server.haengdong.persistence.EventRepository; + +@RequiredArgsConstructor +@Service +public class EventService { + + private final EventRepository eventRepository; + private final EventTokenProvider eventTokenProvider; + + public EventAppResponse saveEvent(EventAppRequest request) { + String token = eventTokenProvider.createToken(); + Event event = request.toEvent(token); + eventRepository.save(event); + + return EventAppResponse.of(event); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/EventAppRequest.java b/server/src/main/java/server/haengdong/application/request/EventAppRequest.java new file mode 100644 index 000000000..8db47eba9 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/EventAppRequest.java @@ -0,0 +1,10 @@ +package server.haengdong.application.request; + +import server.haengdong.domain.Event; + +public record EventAppRequest(String name) { + + public Event toEvent(String token) { + return new Event(name, token); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/EventAppResponse.java b/server/src/main/java/server/haengdong/application/response/EventAppResponse.java new file mode 100644 index 000000000..37b63dec2 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/EventAppResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.Event; + +public record EventAppResponse(String token) { + + public static EventAppResponse of(Event event) { + return new EventAppResponse(event.getToken()); + } +} diff --git a/server/src/main/java/server/haengdong/domain/Event.java b/server/src/main/java/server/haengdong/domain/Event.java index f4a13e4b1..8c24edc4d 100644 --- a/server/src/main/java/server/haengdong/domain/Event.java +++ b/server/src/main/java/server/haengdong/domain/Event.java @@ -20,4 +20,9 @@ public class Event { private String name; private String token; + + public Event(String name, String token) { + this.name = name; + this.token = token; + } } diff --git a/server/src/main/java/server/haengdong/domain/EventTokenProvider.java b/server/src/main/java/server/haengdong/domain/EventTokenProvider.java new file mode 100644 index 000000000..54d455f35 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/EventTokenProvider.java @@ -0,0 +1,12 @@ +package server.haengdong.domain; + +import java.util.UUID; +import org.springframework.stereotype.Component; + +@Component +public class EventTokenProvider { + + public String createToken() { + return UUID.randomUUID().toString(); + } +} diff --git a/server/src/main/java/server/haengdong/persistence/EventRepository.java b/server/src/main/java/server/haengdong/persistence/EventRepository.java new file mode 100644 index 000000000..855fc80ad --- /dev/null +++ b/server/src/main/java/server/haengdong/persistence/EventRepository.java @@ -0,0 +1,9 @@ +package server.haengdong.persistence; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.Event; + +@Repository +public interface EventRepository extends JpaRepository { +} diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java new file mode 100644 index 000000000..5254a78ae --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -0,0 +1,26 @@ +package server.haengdong.presentation; + +import java.net.URI; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.EventService; +import server.haengdong.application.response.EventAppResponse; +import server.haengdong.presentation.request.EventSaveRequest; + +@RequiredArgsConstructor +@RestController +public class EventController { + + private final EventService eventService; + + @PostMapping("/api/events") + public ResponseEntity saveEvent(EventSaveRequest request) { + EventAppResponse eventAppResponse = eventService.saveEvent(request.toAppRequest()); + + return ResponseEntity.ok() + .location(URI.create("events/" + eventAppResponse.token())) + .build(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java new file mode 100644 index 000000000..8bd4cfda8 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java @@ -0,0 +1,10 @@ +package server.haengdong.presentation.request; + +import server.haengdong.application.request.EventAppRequest; + +public record EventSaveRequest(String name) { + + public EventAppRequest toAppRequest() { + return new EventAppRequest(name); + } +} diff --git a/server/src/test/java/server/haengdong/application/EventServiceTest.java b/server/src/test/java/server/haengdong/application/EventServiceTest.java new file mode 100644 index 000000000..5fef04b81 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/EventServiceTest.java @@ -0,0 +1,35 @@ +package server.haengdong.application; + + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.response.EventAppResponse; +import server.haengdong.domain.EventTokenProvider; + +@SpringBootTest +class EventServiceTest { + + @Autowired + private EventService eventService; + + @MockBean + private EventTokenProvider eventTokenProvider; + + @DisplayName("행사를 생성한다") + @Test + void saveEventTest() { + EventAppRequest request = new EventAppRequest("test"); + given(eventTokenProvider.createToken()).willReturn("TOKEN"); + + EventAppResponse response = eventService.saveEvent(request); + + assertThat(response.token()).isEqualTo("TOKEN"); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java new file mode 100644 index 000000000..bed814ae3 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java @@ -0,0 +1,51 @@ +package server.haengdong.presentation; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import server.haengdong.application.EventService; +import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.response.EventAppResponse; +import server.haengdong.presentation.request.EventSaveRequest; + +@WebMvcTest(EventController.class) +class EventControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private EventService eventService; + + @DisplayName("이벤트를 생성한다") + @Test + void saveEvent() throws Exception { + EventSaveRequest eventSaveRequest = new EventSaveRequest("test"); + String requestBody = objectMapper.writeValueAsString(eventSaveRequest); + String token = "TOKEN"; + EventAppResponse eventAppResponse = new EventAppResponse(token); + given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); + + mockMvc.perform(post("/api/events") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.redirectedUrl("events/" + token)); + } +} From 891786565179354b24f6089d58a7e49a5f2846e3 Mon Sep 17 00:00:00 2001 From: Arachneee Date: Thu, 18 Jul 2024 19:39:03 +0900 Subject: [PATCH 047/178] =?UTF-8?q?feat:=20=EC=A7=80=EC=B6=9C=20=EB=82=B4?= =?UTF-8?q?=EC=97=AD=20=EC=B6=94=EA=B0=80=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/build.gradle | 1 + .../application/BillActionService.java | 48 +++++++++++++ .../haengdong/application/EventService.java | 2 +- .../request/BillActionAppRequest.java | 14 ++++ .../java/server/haengdong/domain/Action.java | 5 ++ .../server/haengdong/domain/BillAction.java | 17 +++-- .../persistence/ActionRepository.java | 21 ++++++ .../persistence/BillActionRepository.java | 13 ++++ .../persistence/EventRepository.java | 3 + .../presentation/BillActionController.java | 29 ++++++++ .../request/BillActionSaveRequest.java | 22 ++++++ .../request/BillActionsSaveRequest.java | 13 ++++ .../src/main/resources/application.properties | 1 - server/src/main/resources/application.yml | 15 ++++ .../application/BillActionServiceTest.java | 69 +++++++++++++++++++ .../BillActionControllerTest.java | 53 ++++++++++++++ 16 files changed, 320 insertions(+), 6 deletions(-) create mode 100644 server/src/main/java/server/haengdong/application/BillActionService.java create mode 100644 server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java create mode 100644 server/src/main/java/server/haengdong/persistence/ActionRepository.java create mode 100644 server/src/main/java/server/haengdong/persistence/BillActionRepository.java create mode 100644 server/src/main/java/server/haengdong/presentation/BillActionController.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java delete mode 100644 server/src/main/resources/application.properties create mode 100644 server/src/main/resources/application.yml create mode 100644 server/src/test/java/server/haengdong/application/BillActionServiceTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java diff --git a/server/build.gradle b/server/build.gradle index 43598d638..26f6ec262 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -26,6 +26,7 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-validation' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' runtimeOnly 'com.mysql:mysql-connector-j' diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java new file mode 100644 index 000000000..0aec7f6bd --- /dev/null +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -0,0 +1,48 @@ +package server.haengdong.application; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.BillActionAppRequest; +import server.haengdong.domain.Action; +import server.haengdong.domain.BillAction; +import server.haengdong.domain.Event; +import server.haengdong.persistence.ActionRepository; +import server.haengdong.persistence.BillActionRepository; +import server.haengdong.persistence.EventRepository; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class BillActionService { + + private final EventRepository eventRepository; + private final ActionRepository actionRepository; + private final BillActionRepository billActionRepository; + + @Transactional + public void saveAllBillAction(String eventToken, List requests) { + Event event = eventRepository.findByToken(eventToken) + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 이벤트 토큰입니다.")); + long lastSequence = getLastSequence(event); + + List billActions = new ArrayList<>(); + for (BillActionAppRequest request : requests) { + Action action = new Action(event, ++lastSequence); + BillAction billAction = request.toBillAction(action); + billActions.add(billAction); + } + billActionRepository.saveAll(billActions); + } + + private long getLastSequence(Event event) { + Optional lastAction = actionRepository.findLastByEvent(event); + if (lastAction.isPresent()) { + return lastAction.get().getSequence(); + } + return 0L; + } +} diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java index deac413a4..6a5304e32 100644 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -20,6 +20,6 @@ public EventAppResponse saveEvent(EventAppRequest request) { Event event = request.toEvent(token); eventRepository.save(event); - return EventAppResponse.of(event); + return EventAppResponse.of(event); } } diff --git a/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java new file mode 100644 index 000000000..33c335737 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java @@ -0,0 +1,14 @@ +package server.haengdong.application.request; + +import server.haengdong.domain.Action; +import server.haengdong.domain.BillAction; + +public record BillActionAppRequest( + String title, + Long price +) { + + public BillAction toBillAction(Action action) { + return new BillAction(action, title, price); + } +} diff --git a/server/src/main/java/server/haengdong/domain/Action.java b/server/src/main/java/server/haengdong/domain/Action.java index 7f782a1ac..7a47b1de5 100644 --- a/server/src/main/java/server/haengdong/domain/Action.java +++ b/server/src/main/java/server/haengdong/domain/Action.java @@ -23,4 +23,9 @@ public class Action { private Event event; private Long sequence; + + public Action(Event event, Long sequence) { + this.event = event; + this.sequence = sequence; + } } diff --git a/server/src/main/java/server/haengdong/domain/BillAction.java b/server/src/main/java/server/haengdong/domain/BillAction.java index e70abd644..8c0827445 100644 --- a/server/src/main/java/server/haengdong/domain/BillAction.java +++ b/server/src/main/java/server/haengdong/domain/BillAction.java @@ -1,12 +1,11 @@ package server.haengdong.domain; +import jakarta.persistence.CascadeType; import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.OneToOne; -import java.math.BigDecimal; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -20,10 +19,20 @@ public class BillAction { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @OneToOne(fetch = FetchType.LAZY) + @OneToOne(cascade = CascadeType.PERSIST) private Action action; private String title; - private BigDecimal price; + private Long price; + + public BillAction(Action action, String title, Long price) { + this.action = action; + this.title = title; + this.price = price; + } + + public Long getSequence() { + return action.getSequence(); + } } diff --git a/server/src/main/java/server/haengdong/persistence/ActionRepository.java b/server/src/main/java/server/haengdong/persistence/ActionRepository.java new file mode 100644 index 000000000..72c573d91 --- /dev/null +++ b/server/src/main/java/server/haengdong/persistence/ActionRepository.java @@ -0,0 +1,21 @@ +package server.haengdong.persistence; + +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.Action; +import server.haengdong.domain.Event; + +@Repository +public interface ActionRepository extends JpaRepository { + + @Query(""" + SELECT a + FROM Action a + WHERE a.event = :event + ORDER BY a.sequence DESC + LIMIT 1 + """) + Optional findLastByEvent(Event event); +} diff --git a/server/src/main/java/server/haengdong/persistence/BillActionRepository.java b/server/src/main/java/server/haengdong/persistence/BillActionRepository.java new file mode 100644 index 000000000..96e47237a --- /dev/null +++ b/server/src/main/java/server/haengdong/persistence/BillActionRepository.java @@ -0,0 +1,13 @@ +package server.haengdong.persistence; + +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.BillAction; +import server.haengdong.domain.Event; + +@Repository +public interface BillActionRepository extends JpaRepository { + + List findByAction_Event(Event event); +} diff --git a/server/src/main/java/server/haengdong/persistence/EventRepository.java b/server/src/main/java/server/haengdong/persistence/EventRepository.java index 855fc80ad..8a83d751f 100644 --- a/server/src/main/java/server/haengdong/persistence/EventRepository.java +++ b/server/src/main/java/server/haengdong/persistence/EventRepository.java @@ -1,9 +1,12 @@ package server.haengdong.persistence; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import server.haengdong.domain.Event; @Repository public interface EventRepository extends JpaRepository { + + Optional findByToken(String token); } diff --git a/server/src/main/java/server/haengdong/presentation/BillActionController.java b/server/src/main/java/server/haengdong/presentation/BillActionController.java new file mode 100644 index 000000000..139d6a470 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/BillActionController.java @@ -0,0 +1,29 @@ +package server.haengdong.presentation; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.BillActionService; +import server.haengdong.presentation.request.BillActionsSaveRequest; + +@RequiredArgsConstructor +@RestController +public class BillActionController { + + private final BillActionService billActionService; + + @PostMapping("/api/events/{token}/actions/bills") + public ResponseEntity saveAllBillAction( + @PathVariable String token, + @RequestBody @Valid BillActionsSaveRequest request + ) { + billActionService.saveAllBillAction(token, request.toAppRequests()); + + return ResponseEntity.ok() + .build(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java new file mode 100644 index 000000000..8d662050f --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java @@ -0,0 +1,22 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.Size; +import server.haengdong.application.request.BillActionAppRequest; + +public record BillActionSaveRequest( + + @NotNull + @Size(min = 2, max = 30) + String title, + + @NotNull + @Positive + Long price +) { + + public BillActionAppRequest toAppRequest() { + return new BillActionAppRequest(title, price); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java new file mode 100644 index 000000000..bb16dfda0 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java @@ -0,0 +1,13 @@ +package server.haengdong.presentation.request; + +import java.util.List; +import server.haengdong.application.request.BillActionAppRequest; + +public record BillActionsSaveRequest(List actions) { + + public List toAppRequests() { + return actions.stream() + .map(BillActionSaveRequest::toAppRequest) + .toList(); + } +} diff --git a/server/src/main/resources/application.properties b/server/src/main/resources/application.properties deleted file mode 100644 index df243b894..000000000 --- a/server/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ -spring.application.name=server diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml new file mode 100644 index 000000000..49c481eaa --- /dev/null +++ b/server/src/main/resources/application.yml @@ -0,0 +1,15 @@ +spring: + h2: + console: + enabled: true + path: /h2-console + datasource: + url: jdbc:h2:mem:database + jpa: + defer-datasource-initialization: true + show-sql: true + properties: + hibernate: + format_sql: true + hibernate: + ddl-auto: create-drop diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java new file mode 100644 index 000000000..ba0cfc41a --- /dev/null +++ b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java @@ -0,0 +1,69 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; + +import java.util.Comparator; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import server.haengdong.application.request.BillActionAppRequest; +import server.haengdong.domain.BillAction; +import server.haengdong.domain.Event; +import server.haengdong.persistence.BillActionRepository; +import server.haengdong.persistence.EventRepository; + +@SpringBootTest +class BillActionServiceTest { + + @Autowired + private BillActionService billActionService; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillActionRepository billActionRepository; + + @DisplayName("지출 내역을 생성한다.") + @Test + void saveAllBillAction() { + String token = "TOKEN"; + Event event = eventRepository.save(new Event("감자", token)); + + List requests = List.of( + new BillActionAppRequest("뽕족", 10_000L), + new BillActionAppRequest("인생맥주", 15_000L) + ); + + billActionService.saveAllBillAction(token, requests); + + List actions = billActionRepository.findByAction_Event(event) + .stream() + .sorted(Comparator.comparing(BillAction::getSequence).reversed()) + .limit(requests.size()) + .toList(); + + assertThat(actions).extracting("title", "price") + .containsExactly( + tuple("인생맥주", 15_000L), + tuple("뽕족", 10_000L) + ); + } + + @DisplayName("이벤트가 존재하지 않으면 지출 내역을 생성할 수 없다.") + @Test + void saveAllBillAction1() { + List requests = List.of( + new BillActionAppRequest("뽕족", 10_000L), + new BillActionAppRequest("인생맥주", 15_000L) + ); + + assertThatThrownBy(() -> billActionService.saveAllBillAction("token", requests)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("존재하지 않는 이벤트 토큰입니다."); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java new file mode 100644 index 000000000..a3ae3d5c8 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java @@ -0,0 +1,53 @@ +package server.haengdong.presentation; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import server.haengdong.application.BillActionService; +import server.haengdong.presentation.request.BillActionSaveRequest; +import server.haengdong.presentation.request.BillActionsSaveRequest; + +@WebMvcTest(BillActionController.class) +class BillActionControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private BillActionService billActionService; + + @DisplayName("지출 내역을 생성한다.") + @Test + void saveAllBillAction() throws Exception { + BillActionsSaveRequest request = new BillActionsSaveRequest( + List.of( + new BillActionSaveRequest("뽕족", 10_000L), + new BillActionSaveRequest("인생맥주", 10_000L) + ) + ); + String requestBody = objectMapper.writeValueAsString(request); + String token = "TOKEN"; + doNothing().when(billActionService).saveAllBillAction(any(), any()); + + mockMvc.perform(post("/api/events/{token}/actions/bills", token) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()); + } +} From 9d6aa7b2127d5cfc2e5f50b97e68137344c00cc5 Mon Sep 17 00:00:00 2001 From: juha Date: Fri, 19 Jul 2024 15:54:49 +0900 Subject: [PATCH 048/178] =?UTF-8?q?refactor:=20event=EC=9D=98=20=EB=A7=88?= =?UTF-8?q?=EC=A7=80=EB=A7=89=20action=20=EC=88=9C=EC=84=9C=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/haengdong/application/BillActionService.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java index 0aec7f6bd..3f85b0da1 100644 --- a/server/src/main/java/server/haengdong/application/BillActionService.java +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -39,10 +39,8 @@ public void saveAllBillAction(String eventToken, List requ } private long getLastSequence(Event event) { - Optional lastAction = actionRepository.findLastByEvent(event); - if (lastAction.isPresent()) { - return lastAction.get().getSequence(); - } - return 0L; + return actionRepository.findLastByEvent(event) + .map(Action::getSequence) + .orElse(0L); } } From 75ee0137d3680b45cade6f9d8cb6d4e22c4ea7d1 Mon Sep 17 00:00:00 2001 From: juha Date: Fri, 19 Jul 2024 16:00:31 +0900 Subject: [PATCH 049/178] =?UTF-8?q?refactor:=20BillAction=20fetch=20type?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/main/java/server/haengdong/domain/BillAction.java | 3 ++- .../server/haengdong/persistence/BillActionRepository.java | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/server/haengdong/domain/BillAction.java b/server/src/main/java/server/haengdong/domain/BillAction.java index 8c0827445..24ab5a410 100644 --- a/server/src/main/java/server/haengdong/domain/BillAction.java +++ b/server/src/main/java/server/haengdong/domain/BillAction.java @@ -2,6 +2,7 @@ import jakarta.persistence.CascadeType; import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; @@ -19,7 +20,7 @@ public class BillAction { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @OneToOne(cascade = CascadeType.PERSIST) + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) private Action action; private String title; diff --git a/server/src/main/java/server/haengdong/persistence/BillActionRepository.java b/server/src/main/java/server/haengdong/persistence/BillActionRepository.java index 96e47237a..03db3056e 100644 --- a/server/src/main/java/server/haengdong/persistence/BillActionRepository.java +++ b/server/src/main/java/server/haengdong/persistence/BillActionRepository.java @@ -1,6 +1,7 @@ package server.haengdong.persistence; import java.util.List; +import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import server.haengdong.domain.BillAction; @@ -9,5 +10,6 @@ @Repository public interface BillActionRepository extends JpaRepository { + @EntityGraph(attributePaths = {"action"}) List findByAction_Event(Event event); } From ba220205f0a3d6f56459f689bd6c007bfd0dadb3 Mon Sep 17 00:00:00 2001 From: juha Date: Fri, 19 Jul 2024 16:04:56 +0900 Subject: [PATCH 050/178] =?UTF-8?q?test:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20mocking=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../haengdong/presentation/BillActionControllerTest.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java index a3ae3d5c8..f37ad109f 100644 --- a/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java @@ -1,7 +1,5 @@ package server.haengdong.presentation; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doNothing; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -42,7 +40,6 @@ void saveAllBillAction() throws Exception { ); String requestBody = objectMapper.writeValueAsString(request); String token = "TOKEN"; - doNothing().when(billActionService).saveAllBillAction(any(), any()); mockMvc.perform(post("/api/events/{token}/actions/bills", token) .contentType(MediaType.APPLICATION_JSON) From 5ec0c4cbd7bb79523d846b7c88e6db2aa2d871c5 Mon Sep 17 00:00:00 2001 From: juha Date: Fri, 19 Jul 2024 16:09:07 +0900 Subject: [PATCH 051/178] =?UTF-8?q?refactor:=20=EC=A4=91=EC=9A=94=EB=8F=84?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=9D=BC=20=ED=95=84=EB=93=9C=20=EC=88=9C?= =?UTF-8?q?=EC=84=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/server/haengdong/application/BillActionService.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java index 3f85b0da1..6c69e383f 100644 --- a/server/src/main/java/server/haengdong/application/BillActionService.java +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -2,7 +2,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -19,9 +18,9 @@ @Service public class BillActionService { - private final EventRepository eventRepository; - private final ActionRepository actionRepository; private final BillActionRepository billActionRepository; + private final ActionRepository actionRepository; + private final EventRepository eventRepository; @Transactional public void saveAllBillAction(String eventToken, List requests) { From ced5660f160516954bfb0bbc50cc0bc7bf386b3a Mon Sep 17 00:00:00 2001 From: juha Date: Fri, 19 Jul 2024 16:26:14 +0900 Subject: [PATCH 052/178] =?UTF-8?q?fix:=20BillAction=20=EC=A0=80=EC=9E=A5?= =?UTF-8?q?=20Dto=20=EA=B2=80=EC=A6=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/BillActionsSaveRequest.java | 3 ++- .../BillActionControllerTest.java | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java index bb16dfda0..68784039b 100644 --- a/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java @@ -1,9 +1,10 @@ package server.haengdong.presentation.request; +import jakarta.validation.Valid; import java.util.List; import server.haengdong.application.request.BillActionAppRequest; -public record BillActionsSaveRequest(List actions) { +public record BillActionsSaveRequest(@Valid List actions) { public List toAppRequests() { return actions.stream() diff --git a/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java index f37ad109f..8bf2b292f 100644 --- a/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java @@ -47,4 +47,23 @@ void saveAllBillAction() throws Exception { .andDo(print()) .andExpect(status().isOk()); } + + @DisplayName("title이 비어 있는 경우 지출 내역을 생성할 수 없다.") + @Test + void saveAllBillAction1() throws Exception { + BillActionsSaveRequest request = new BillActionsSaveRequest( + List.of( + new BillActionSaveRequest("", 10_000L), + new BillActionSaveRequest("인생맥주", 10_000L) + ) + ); + String requestBody = objectMapper.writeValueAsString(request); + String token = "TOKEN"; + + mockMvc.perform(post("/api/events/{token}/actions/bills", token) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isBadRequest()); + } } From 3d09f4503d4a70af3a2b685c860a0686d9799148 Mon Sep 17 00:00:00 2001 From: TaehunLee <85233397+Todari@users.noreply.github.com> Date: Fri, 19 Jul 2024 17:38:49 +0900 Subject: [PATCH 053/178] =?UTF-8?q?[FE]=20=EB=94=94=EC=9E=90=EC=9D=B8=20?= =?UTF-8?q?=EC=8B=9C=EC=8A=A4=ED=85=9C=20=EC=88=98=EC=A0=95=20(#46)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: storybook 관련 dependency 설치 * fix: Text component 수정 * feat: TextButton Component 구현 * fix: Title Component 수정 * feat: input component background color InputType 추가 및 입력제거 아이콘 변경 * feat: Switch component 구현 * feat: TopNav component 구현 * feat: Tab 컴포넌트 구현 * refactor: Tab type type.ts로 분리 * feature: ExpenseList component 구현 * design: 폰트 size, weight, color 수정 * feat: BillItem에 드래그핸들러 포함 여부를 props로 받을 수 있도록 구현 * design: 드래그핸들러 여부에 따라 패딩을 다르게 하도록 수정 * feat: Flex 컴포넌트 구현 * feat: 잡고 이동할 수 있는 DragHandleItem 컴포넌트 모습 구현 아직 잡고 이동하는 기능은 없습니다. * chore: DragHandleItem 컴포넌트의 스토리북 작성 * feat: BillItem 컴포넌트가 DragHandleItem, Flex 컴포넌트를 사용하도록 수정 * feat: InOutItem 컴포넌트가 DragHandleItem, Flex 컴포넌트를 사용하도록 수정 * fix: 스토리북에서 배열 형태로 모습 테스트를 할 수 있도록 type 수정 * feat: InOutItem에서 드래그 여부를 할 수 있도록 type 추가 * feat: StepItem 컴포넌트가 Flex 컴포넌트를 사용하도록 대체 * feat: children을 포함하는 타입을 빠르게 선언하기 위한 타입 구현 * feat: 카멜 케이스를 케밥 케이스의 문자열로 반환하는 함수 구현 * design: 사용하지 않게된 css 객체 제거 * feat: COLORS 자동완성을 위한 타입 추가 --------- Co-authored-by: 김진호 Co-authored-by: Soyeon Choe Co-authored-by: pakxe --- HDesign/package-lock.json | 218 ++---------------- HDesign/package.json | 2 + HDesign/src/assets/arrow.svg | 3 + HDesign/src/assets/index.ts | 1 + HDesign/src/assets/inputDelete.svg | 6 +- .../src/components/BillItem/BillItem.style.ts | 14 -- HDesign/src/components/BillItem/BillItem.tsx | 32 +-- .../src/components/BillItem/BillItem.type.ts | 1 + .../DragHandleItem/DragHandleItem.stories.tsx | 31 +++ .../DragHandleItem/DragHandleItem.style.ts | 18 ++ .../DragHandleItem/DragHandleItem.tsx | 36 +++ .../ExpenseList/ExpenseList.stories.tsx | 29 +++ .../ExpenseList/ExpenseList.style.ts | 33 +++ .../components/ExpenseList/ExpenseList.tsx | 37 +++ .../ExpenseList/ExpenseList.type.ts | 8 + HDesign/src/components/Flex/Flex.tsx | 39 ++++ HDesign/src/components/Flex/Flex.type.ts | 18 ++ .../InOutItem/InOutItem.stories.tsx | 2 +- .../src/components/InOutItem/InOutItem.tsx | 23 +- .../components/InOutItem/InOutItem.type.ts | 1 + .../src/components/Input/Input.stories.tsx | 4 + HDesign/src/components/Input/Input.style.ts | 18 +- HDesign/src/components/Input/Input.tsx | 4 +- HDesign/src/components/Input/Input.type.ts | 6 +- .../src/components/StepItem/StepItem.style.ts | 14 +- HDesign/src/components/StepItem/StepItem.tsx | 23 +- .../src/components/Switch/Switch.stories.tsx | 39 ++++ HDesign/src/components/Switch/Switch.style.ts | 6 + HDesign/src/components/Switch/Switch.tsx | 26 +++ HDesign/src/components/Switch/Switch.type.ts | 6 + HDesign/src/components/Switch/useSwitch.ts | 24 ++ HDesign/src/components/Tab/Tab.stories.tsx | 25 ++ HDesign/src/components/Tab/Tab.style.ts | 51 ++++ HDesign/src/components/Tab/Tab.tsx | 54 +++++ HDesign/src/components/Tab/Tab.type.ts | 8 + HDesign/src/components/Text/Text.style.ts | 4 +- HDesign/src/components/Text/Text.tsx | 8 +- HDesign/src/components/Text/Text.type.ts | 22 +- .../TextButton/TextButton.stories.tsx | 50 ++++ .../components/TextButton/TextButton.style.ts | 13 ++ .../src/components/TextButton/TextButton.tsx | 23 ++ .../components/TextButton/TextButton.type.ts | 15 ++ .../src/components/Title/Title.stories.tsx | 5 + HDesign/src/components/Title/Title.style.ts | 31 ++- HDesign/src/components/Title/Title.tsx | 27 ++- HDesign/src/components/Title/Title.type.ts | 1 + .../src/components/TopNav/TopNav.stories.ts | 28 +++ HDesign/src/components/TopNav/TopNav.style.ts | 6 + HDesign/src/components/TopNav/TopNav.tsx | 24 ++ HDesign/src/components/TopNav/TopNav.type.ts | 5 + HDesign/src/token/colors.ts | 15 +- HDesign/src/types/strictPropsWithChildren.ts | 3 + .../changeCamelCaseToKebabCase.ts | 3 + 53 files changed, 843 insertions(+), 300 deletions(-) create mode 100644 HDesign/src/assets/arrow.svg create mode 100644 HDesign/src/components/DragHandleItem/DragHandleItem.stories.tsx create mode 100644 HDesign/src/components/DragHandleItem/DragHandleItem.style.ts create mode 100644 HDesign/src/components/DragHandleItem/DragHandleItem.tsx create mode 100644 HDesign/src/components/ExpenseList/ExpenseList.stories.tsx create mode 100644 HDesign/src/components/ExpenseList/ExpenseList.style.ts create mode 100644 HDesign/src/components/ExpenseList/ExpenseList.tsx create mode 100644 HDesign/src/components/ExpenseList/ExpenseList.type.ts create mode 100644 HDesign/src/components/Flex/Flex.tsx create mode 100644 HDesign/src/components/Flex/Flex.type.ts create mode 100644 HDesign/src/components/Switch/Switch.stories.tsx create mode 100644 HDesign/src/components/Switch/Switch.style.ts create mode 100644 HDesign/src/components/Switch/Switch.tsx create mode 100644 HDesign/src/components/Switch/Switch.type.ts create mode 100644 HDesign/src/components/Switch/useSwitch.ts create mode 100644 HDesign/src/components/Tab/Tab.stories.tsx create mode 100644 HDesign/src/components/Tab/Tab.style.ts create mode 100644 HDesign/src/components/Tab/Tab.tsx create mode 100644 HDesign/src/components/Tab/Tab.type.ts create mode 100644 HDesign/src/components/TextButton/TextButton.stories.tsx create mode 100644 HDesign/src/components/TextButton/TextButton.style.ts create mode 100644 HDesign/src/components/TextButton/TextButton.tsx create mode 100644 HDesign/src/components/TextButton/TextButton.type.ts create mode 100644 HDesign/src/components/TopNav/TopNav.stories.ts create mode 100644 HDesign/src/components/TopNav/TopNav.style.ts create mode 100644 HDesign/src/components/TopNav/TopNav.tsx create mode 100644 HDesign/src/components/TopNav/TopNav.type.ts create mode 100644 HDesign/src/types/strictPropsWithChildren.ts create mode 100644 HDesign/src/utils/ return str.replace(/([a-z])([A-Z])/changeCamelCaseToKebabCase.ts diff --git a/HDesign/package-lock.json b/HDesign/package-lock.json index 28469fd93..905b380c5 100644 --- a/HDesign/package-lock.json +++ b/HDesign/package-lock.json @@ -10,6 +10,7 @@ "license": "ISC", "dependencies": { "@emotion/react": "^11.11.4", + "@svgr/webpack": "^8.1.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.24.1" @@ -27,7 +28,6 @@ "@storybook/react": "^8.2.2", "@storybook/react-webpack5": "^8.2.3", "@storybook/test": "^8.2.2", - "@svgr/webpack": "^8.1.0", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "@typescript-eslint/eslint-plugin": "^7.16.0", @@ -65,7 +65,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -90,7 +89,6 @@ "version": "7.24.9", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.9.tgz", "integrity": "sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -99,7 +97,6 @@ "version": "7.24.9", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz", "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==", - "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.7", @@ -128,14 +125,12 @@ "node_modules/@babel/core/node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, "node_modules/@babel/core/node_modules/debug": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -151,14 +146,12 @@ "node_modules/@babel/core/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "bin": { "semver": "bin/semver.js" } @@ -181,7 +174,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", - "dev": true, "dependencies": { "@babel/types": "^7.24.7" }, @@ -193,7 +185,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", - "dev": true, "dependencies": { "@babel/traverse": "^7.24.7", "@babel/types": "^7.24.7" @@ -206,7 +197,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz", "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==", - "dev": true, "dependencies": { "@babel/compat-data": "^7.24.8", "@babel/helper-validator-option": "^7.24.8", @@ -222,7 +212,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, "dependencies": { "yallist": "^3.0.2" } @@ -231,7 +220,6 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "bin": { "semver": "bin/semver.js" } @@ -240,7 +228,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.8.tgz", "integrity": "sha512-4f6Oqnmyp2PP3olgUMmOwC3akxSm5aBYraQ6YDdKy7NcAMkDECHWG0DEnV6M2UAkERgIBhYt8S27rURPg7SxWA==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-environment-visitor": "^7.24.7", @@ -263,7 +250,6 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "bin": { "semver": "bin/semver.js" } @@ -272,7 +258,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.7.tgz", "integrity": "sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "regexpu-core": "^5.3.1", @@ -289,7 +274,6 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "bin": { "semver": "bin/semver.js" } @@ -298,7 +282,6 @@ "version": "0.6.2", "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", - "dev": true, "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", @@ -314,7 +297,6 @@ "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -330,8 +312,7 @@ "node_modules/@babel/helper-define-polyfill-provider/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/@babel/helper-environment-visitor": { "version": "7.24.7", @@ -371,7 +352,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", - "dev": true, "dependencies": { "@babel/traverse": "^7.24.8", "@babel/types": "^7.24.8" @@ -396,7 +376,6 @@ "version": "7.24.9", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz", "integrity": "sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==", - "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.24.7", "@babel/helper-module-imports": "^7.24.7", @@ -415,7 +394,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", - "dev": true, "dependencies": { "@babel/types": "^7.24.7" }, @@ -427,7 +405,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -436,7 +413,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.7.tgz", "integrity": "sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-environment-visitor": "^7.24.7", @@ -453,7 +429,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz", "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==", - "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.24.7", "@babel/helper-member-expression-to-functions": "^7.24.7", @@ -470,7 +445,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", - "dev": true, "dependencies": { "@babel/traverse": "^7.24.7", "@babel/types": "^7.24.7" @@ -483,7 +457,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", - "dev": true, "dependencies": { "@babel/traverse": "^7.24.7", "@babel/types": "^7.24.7" @@ -523,7 +496,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -532,7 +504,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.7.tgz", "integrity": "sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==", - "dev": true, "dependencies": { "@babel/helper-function-name": "^7.24.7", "@babel/template": "^7.24.7", @@ -547,7 +518,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz", "integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==", - "dev": true, "dependencies": { "@babel/template": "^7.24.7", "@babel/types": "^7.24.8" @@ -641,7 +611,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.7.tgz", "integrity": "sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==", - "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -657,7 +626,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.7.tgz", "integrity": "sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -672,7 +640,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", @@ -689,7 +656,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.7.tgz", "integrity": "sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==", - "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -705,7 +671,6 @@ "version": "7.21.0-placeholder-for-preset-env.2", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "dev": true, "engines": { "node": ">=6.9.0" }, @@ -717,7 +682,6 @@ "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -729,7 +693,6 @@ "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" }, @@ -741,7 +704,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -756,7 +718,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -768,7 +729,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.3" }, @@ -795,7 +755,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -810,7 +769,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -825,7 +783,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -837,7 +794,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -849,7 +805,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -864,7 +819,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -876,7 +830,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -888,7 +841,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -900,7 +852,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -912,7 +863,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -924,7 +874,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -936,7 +885,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -951,7 +899,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -966,7 +913,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -981,7 +927,6 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", - "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -997,7 +942,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1012,7 +956,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.7.tgz", "integrity": "sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==", - "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7", @@ -1030,7 +973,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", - "dev": true, "dependencies": { "@babel/helper-module-imports": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7", @@ -1047,7 +989,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1062,7 +1003,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.7.tgz", "integrity": "sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1077,7 +1017,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz", "integrity": "sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==", - "dev": true, "dependencies": { "@babel/helper-create-class-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1093,7 +1032,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", - "dev": true, "dependencies": { "@babel/helper-create-class-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7", @@ -1110,7 +1048,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.8.tgz", "integrity": "sha512-VXy91c47uujj758ud9wx+OMgheXm4qJfyhj1P18YvlrQkNOSrwsteHk+EFS3OMGfhMhpZa0A+81eE7G4QC+3CA==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-compilation-targets": "^7.24.8", @@ -1132,7 +1069,6 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, "engines": { "node": ">=4" } @@ -1141,7 +1077,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/template": "^7.24.7" @@ -1157,7 +1092,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.8" }, @@ -1172,7 +1106,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", - "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1188,7 +1121,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1203,7 +1135,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3" @@ -1219,7 +1150,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", - "dev": true, "dependencies": { "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1235,7 +1165,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" @@ -1267,7 +1196,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" @@ -1283,7 +1211,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.7.tgz", "integrity": "sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==", - "dev": true, "dependencies": { "@babel/helper-compilation-targets": "^7.24.7", "@babel/helper-function-name": "^7.24.7", @@ -1300,7 +1227,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-json-strings": "^7.8.3" @@ -1316,7 +1242,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.7.tgz", "integrity": "sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1331,7 +1256,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" @@ -1347,7 +1271,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1362,7 +1285,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", - "dev": true, "dependencies": { "@babel/helper-module-transforms": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1378,7 +1300,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", - "dev": true, "dependencies": { "@babel/helper-module-transforms": "^7.24.8", "@babel/helper-plugin-utils": "^7.24.8", @@ -1395,7 +1316,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.7.tgz", "integrity": "sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==", - "dev": true, "dependencies": { "@babel/helper-hoist-variables": "^7.24.7", "@babel/helper-module-transforms": "^7.24.7", @@ -1413,7 +1333,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", - "dev": true, "dependencies": { "@babel/helper-module-transforms": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1429,7 +1348,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", - "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1445,7 +1363,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1460,7 +1377,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" @@ -1476,7 +1392,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-numeric-separator": "^7.10.4" @@ -1492,7 +1407,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", - "dev": true, "dependencies": { "@babel/helper-compilation-targets": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7", @@ -1510,7 +1424,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-replace-supers": "^7.24.7" @@ -1526,7 +1439,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" @@ -1542,7 +1454,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.8", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", @@ -1559,7 +1470,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1574,7 +1484,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz", "integrity": "sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==", - "dev": true, "dependencies": { "@babel/helper-create-class-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1590,7 +1499,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-create-class-features-plugin": "^7.24.7", @@ -1608,7 +1516,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1623,7 +1530,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.24.7.tgz", "integrity": "sha512-7LidzZfUXyfZ8/buRW6qIIHBY8wAZ1OrY9c/wTr8YhZ6vMPo+Uc/CVFLYY1spZrEQlD4w5u8wjqk5NQ3OVqQKA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1638,7 +1544,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.7.tgz", "integrity": "sha512-H/Snz9PFxKsS1JLI4dJLtnJgCJRoo0AUm3chP6NYr+9En1JMKloheEiLIhlp5MDVznWo+H3AAC1Mc8lmUEpsgg==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1653,7 +1558,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.24.7.tgz", "integrity": "sha512-+Dj06GDZEFRYvclU6k4bme55GKBEWUmByM/eoKuqg4zTNQHiApWRhQph5fxQB2wAEFvRzL1tOEj1RJ19wJrhoA==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-module-imports": "^7.24.7", @@ -1672,7 +1576,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.24.7.tgz", "integrity": "sha512-QG9EnzoGn+Qar7rxuW+ZOsbWOt56FvvI93xInqsZDC5fsekx1AlIO4KIJ5M+D0p0SqSH156EpmZyXq630B8OlQ==", - "dev": true, "dependencies": { "@babel/plugin-transform-react-jsx": "^7.24.7" }, @@ -1687,7 +1590,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.7.tgz", "integrity": "sha512-PLgBVk3fzbmEjBJ/u8kFzOqS9tUeDjiaWud/rRym/yjCo/M9cASPlnrd2ZmmZpQT40fOOrvR8jh+n8jikrOhNA==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1703,7 +1605,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "regenerator-transform": "^0.15.2" @@ -1719,7 +1620,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1734,7 +1634,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1749,7 +1648,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" @@ -1765,7 +1663,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1780,7 +1677,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1795,7 +1691,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.8" }, @@ -1810,7 +1705,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.8.tgz", "integrity": "sha512-CgFgtN61BbdOGCP4fLaAMOPkzWUh6yQZNMr5YSt8uz2cZSSiQONCQFWqsE4NeVfOIhqDOlS9CR3WD91FzMeB2Q==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-create-class-features-plugin": "^7.24.8", @@ -1828,7 +1722,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1843,7 +1736,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", - "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1859,7 +1751,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", - "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1875,7 +1766,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz", "integrity": "sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==", - "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1891,7 +1781,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.8.tgz", "integrity": "sha512-vObvMZB6hNWuDxhSaEPTKCwcqkAIuDtE+bQGn4XMXne1DSLzFVY8Vmj1bm+mUQXYNN8NmaQEO+r8MMbzPr1jBQ==", - "dev": true, "dependencies": { "@babel/compat-data": "^7.24.8", "@babel/helper-compilation-targets": "^7.24.8", @@ -1986,7 +1875,6 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "bin": { "semver": "bin/semver.js" } @@ -2012,7 +1900,6 @@ "version": "0.1.6-no-external-plugins", "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/types": "^7.4.4", @@ -2026,7 +1913,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.24.7.tgz", "integrity": "sha512-AAH4lEkpmzFWrGVlHaxJB7RLH21uPQ9+He+eFLWHmF9IuFQVugz8eAsamaW0DXRrTfco5zj1wWtpdcXJUOfsag==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-validator-option": "^7.24.7", @@ -2046,7 +1932,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.7.tgz", "integrity": "sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-validator-option": "^7.24.7", @@ -2177,8 +2062,7 @@ "node_modules/@babel/regjsgen": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", - "dev": true + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "node_modules/@babel/runtime": { "version": "7.24.8", @@ -4267,7 +4151,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", - "dev": true, "engines": { "node": ">=14" }, @@ -4283,7 +4166,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", - "dev": true, "engines": { "node": ">=14" }, @@ -4299,7 +4181,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", - "dev": true, "engines": { "node": ">=14" }, @@ -4315,7 +4196,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", - "dev": true, "engines": { "node": ">=14" }, @@ -4331,7 +4211,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", - "dev": true, "engines": { "node": ">=14" }, @@ -4347,7 +4226,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", - "dev": true, "engines": { "node": ">=14" }, @@ -4363,7 +4241,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", - "dev": true, "engines": { "node": ">=14" }, @@ -4379,7 +4256,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", - "dev": true, "engines": { "node": ">=12" }, @@ -4395,7 +4271,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", - "dev": true, "dependencies": { "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", @@ -4421,7 +4296,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", - "dev": true, "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", @@ -4441,7 +4315,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", - "dev": true, "dependencies": { "@babel/types": "^7.21.3", "entities": "^4.4.0" @@ -4458,7 +4331,6 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, "engines": { "node": ">=0.12" }, @@ -4470,7 +4342,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", - "dev": true, "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", @@ -4492,7 +4363,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", - "dev": true, "dependencies": { "cosmiconfig": "^8.1.3", "deepmerge": "^4.3.1", @@ -4513,7 +4383,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", - "dev": true, "dependencies": { "@babel/core": "^7.21.3", "@babel/plugin-transform-react-constant-elements": "^7.21.3", @@ -4866,7 +4735,6 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", - "dev": true, "engines": { "node": ">=10.13.0" } @@ -5981,8 +5849,7 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/aria-query": { "version": "5.1.3", @@ -6272,7 +6139,6 @@ "version": "0.4.11", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", - "dev": true, "dependencies": { "@babel/compat-data": "^7.22.6", "@babel/helper-define-polyfill-provider": "^0.6.2", @@ -6286,7 +6152,6 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "bin": { "semver": "bin/semver.js" } @@ -6295,7 +6160,6 @@ "version": "0.10.4", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz", "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==", - "dev": true, "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.1", "core-js-compat": "^3.36.1" @@ -6308,7 +6172,6 @@ "version": "0.6.2", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", - "dev": true, "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.2" }, @@ -6410,8 +6273,7 @@ "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" }, "node_modules/brace-expansion": { "version": "2.0.1", @@ -6444,7 +6306,6 @@ "version": "4.23.2", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", - "dev": true, "funding": [ { "type": "opencollective", @@ -6543,7 +6404,6 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, "engines": { "node": ">=10" }, @@ -6555,7 +6415,6 @@ "version": "1.0.30001642", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz", "integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==", - "dev": true, "funding": [ { "type": "opencollective", @@ -6891,7 +6750,6 @@ "version": "3.37.1", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", - "dev": true, "dependencies": { "browserslist": "^4.23.0" }, @@ -6904,7 +6762,6 @@ "version": "8.3.6", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dev": true, "dependencies": { "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", @@ -7022,7 +6879,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dev": true, "dependencies": { "mdn-data": "2.0.30", "source-map-js": "^1.0.1" @@ -7035,7 +6891,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "dev": true, "engines": { "node": ">= 6" }, @@ -7065,7 +6920,6 @@ "version": "5.0.5", "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", - "dev": true, "dependencies": { "css-tree": "~2.2.0" }, @@ -7078,7 +6932,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", - "dev": true, "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" @@ -7091,8 +6944,7 @@ "node_modules/csso/node_modules/mdn-data": { "version": "2.0.28", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", - "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", - "dev": true + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==" }, "node_modules/csstype": { "version": "3.1.3", @@ -7231,7 +7083,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -7391,7 +7242,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, "funding": [ { "type": "github", @@ -7432,7 +7282,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "dev": true, "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" @@ -7447,8 +7296,7 @@ "node_modules/electron-to-chromium": { "version": "1.4.827", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.827.tgz", - "integrity": "sha512-VY+J0e4SFcNfQy19MEoMdaIcZLmDCprqvBtkii1WTCTQHpRvf5N8+3kTYCgL/PcntvwQvmMJWTuDPsq+IlhWKQ==", - "dev": true + "integrity": "sha512-VY+J0e4SFcNfQy19MEoMdaIcZLmDCprqvBtkii1WTCTQHpRvf5N8+3kTYCgL/PcntvwQvmMJWTuDPsq+IlhWKQ==" }, "node_modules/emoji-regex": { "version": "9.2.2", @@ -7794,7 +7642,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "dev": true, "engines": { "node": ">=6" } @@ -8687,7 +8534,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -9161,7 +9007,6 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -10234,7 +10079,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -10319,7 +10163,6 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, "bin": { "json5": "lib/cli.js" }, @@ -10470,8 +10313,7 @@ "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -10519,7 +10361,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dev": true, "dependencies": { "tslib": "^2.0.3" } @@ -10587,8 +10428,7 @@ "node_modules/mdn-data": { "version": "2.0.30", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" }, "node_modules/media-typer": { "version": "0.3.0", @@ -10843,7 +10683,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dev": true, "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" @@ -10898,8 +10737,7 @@ "node_modules/node-releases": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -10926,7 +10764,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dev": true, "dependencies": { "boolbase": "^1.0.0" }, @@ -12134,14 +11971,12 @@ "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" }, "node_modules/regenerate-unicode-properties": { "version": "10.1.1", "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", - "dev": true, "dependencies": { "regenerate": "^1.4.2" }, @@ -12158,7 +11993,6 @@ "version": "0.15.2", "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", - "dev": true, "dependencies": { "@babel/runtime": "^7.8.4" } @@ -12185,7 +12019,6 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", - "dev": true, "dependencies": { "@babel/regjsgen": "^0.8.0", "regenerate": "^1.4.2", @@ -12202,7 +12035,6 @@ "version": "0.9.1", "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", - "dev": true, "dependencies": { "jsesc": "~0.5.0" }, @@ -12214,7 +12046,6 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "dev": true, "bin": { "jsesc": "bin/jsesc" } @@ -12638,7 +12469,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", - "dev": true, "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" @@ -12657,7 +12487,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -13087,14 +12916,12 @@ "node_modules/svg-parser": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", - "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", - "dev": true + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" }, "node_modules/svgo": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", - "dev": true, "dependencies": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", @@ -13119,7 +12946,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true, "engines": { "node": ">= 10" } @@ -13128,7 +12954,6 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "dev": true, "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -13144,7 +12969,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -13158,7 +12982,6 @@ "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, "dependencies": { "domelementtype": "^2.3.0" }, @@ -13173,7 +12996,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "dev": true, "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", @@ -13187,7 +13009,6 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, "engines": { "node": ">=0.12" }, @@ -13576,8 +13397,7 @@ "node_modules/tslib": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/tsutils": { "version": "3.21.0", @@ -13817,7 +13637,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "dev": true, "engines": { "node": ">=4" } @@ -13826,7 +13645,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", "unicode-property-aliases-ecmascript": "^2.0.0" @@ -13839,7 +13657,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", - "dev": true, "engines": { "node": ">=4" } @@ -13848,7 +13665,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", - "dev": true, "engines": { "node": ">=4" } @@ -13959,7 +13775,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -14319,8 +14134,7 @@ "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/yaml": { "version": "1.10.2", diff --git a/HDesign/package.json b/HDesign/package.json index afa1bc6e4..c7dbfca71 100644 --- a/HDesign/package.json +++ b/HDesign/package.json @@ -27,6 +27,7 @@ "@storybook/addon-interactions": "^8.2.2", "@storybook/addon-links": "^8.2.2", "@storybook/addon-onboarding": "^8.2.2", + "@storybook/addon-webpack5-compiler-swc": "^1.0.4", "@storybook/blocks": "^8.2.2", "@storybook/react": "^8.2.2", "@storybook/react-webpack5": "^8.2.3", @@ -55,6 +56,7 @@ }, "dependencies": { "@emotion/react": "^11.11.4", + "@svgr/webpack": "^8.1.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.24.1" diff --git a/HDesign/src/assets/arrow.svg b/HDesign/src/assets/arrow.svg new file mode 100644 index 000000000..4d8bac605 --- /dev/null +++ b/HDesign/src/assets/arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/HDesign/src/assets/index.ts b/HDesign/src/assets/index.ts index b531ccc25..3f92063cd 100644 --- a/HDesign/src/assets/index.ts +++ b/HDesign/src/assets/index.ts @@ -1,3 +1,4 @@ export {default as InputDelete} from '@assets/inputDelete.svg'; export {default as Plus} from '@assets/plus.svg'; export {default as Buljusa} from '@assets/buljusa.svg'; +export {default as Arrow} from '@assets/arrow.svg'; diff --git a/HDesign/src/assets/inputDelete.svg b/HDesign/src/assets/inputDelete.svg index 7d3627744..06d850889 100644 --- a/HDesign/src/assets/inputDelete.svg +++ b/HDesign/src/assets/inputDelete.svg @@ -1,4 +1,4 @@ - - - + + + diff --git a/HDesign/src/components/BillItem/BillItem.style.ts b/HDesign/src/components/BillItem/BillItem.style.ts index 7d1c37c30..dceb9af92 100644 --- a/HDesign/src/components/BillItem/BillItem.style.ts +++ b/HDesign/src/components/BillItem/BillItem.style.ts @@ -1,20 +1,6 @@ import {Theme} from '@/theme/theme.type'; import {css} from '@emotion/react'; -export const billItemStyle = (theme: Theme) => - css({ - display: 'flex', - justifyContent: 'space-between', - padding: '0.5rem 0.5rem 0.5rem 0.25rem', - borderRadius: '0.5rem', - backgroundColor: theme.colors.lightGrayContainer, - }); - -export const prefixStyle = css({ - display: 'flex', - gap: '0.25rem', -}); - export const textStyle = (theme: Theme) => css({ color: theme.colors.black, diff --git a/HDesign/src/components/BillItem/BillItem.tsx b/HDesign/src/components/BillItem/BillItem.tsx index 7af1216d2..0823d8add 100644 --- a/HDesign/src/components/BillItem/BillItem.tsx +++ b/HDesign/src/components/BillItem/BillItem.tsx @@ -1,28 +1,30 @@ /** @jsxImportSource @emotion/react */ -import {css} from '@emotion/react'; import React from 'react'; - import {useTheme} from '@theme/HDesignProvider'; - import {BillItemProps} from './BillItem.type'; -import {billItemStyle, prefixStyle, textStyle} from './BillItem.style'; +import {textStyle} from './BillItem.style'; import Text from '@components/Text/Text'; -import IconButton from '../IconButton/IconButton'; +import DragHandleItem from '../DragHandleItem/DragHandleItem'; +import Flex from '../Flex/Flex'; -export const BillItem: React.FC = ({name = '', price = 0, ...htmlProps}: BillItemProps) => { +export const BillItem: React.FC = ({ + name = '', + price = 0, + hasDragHandle = false, + ...htmlProps +}: BillItemProps) => { const {theme} = useTheme(); return ( -
-
- - + + + {name} -
- - {price.toLocaleString('ko-kr')} 원 - -
+ + {price.toLocaleString('ko-kr')} 원 + + + ); }; export default BillItem; diff --git a/HDesign/src/components/BillItem/BillItem.type.ts b/HDesign/src/components/BillItem/BillItem.type.ts index 0fb48b8be..4d6487ac9 100644 --- a/HDesign/src/components/BillItem/BillItem.type.ts +++ b/HDesign/src/components/BillItem/BillItem.type.ts @@ -3,6 +3,7 @@ export interface BillItemStyleProps {} export interface BillItemCustomProps { name?: string; price?: number; + hasDragHandle?: boolean; } export type BillItemOptionProps = BillItemStyleProps & BillItemCustomProps; diff --git a/HDesign/src/components/DragHandleItem/DragHandleItem.stories.tsx b/HDesign/src/components/DragHandleItem/DragHandleItem.stories.tsx new file mode 100644 index 000000000..773c181a2 --- /dev/null +++ b/HDesign/src/components/DragHandleItem/DragHandleItem.stories.tsx @@ -0,0 +1,31 @@ +import type {Meta, StoryObj} from '@storybook/react'; + +import DragHandleItem from '@components/DragHandleItem/DragHandleItem'; + +const meta = { + title: 'Components/DragHandleItem', + component: DragHandleItem, + tags: ['autodocs'], + parameters: {}, + argTypes: { + backgroundColor: { + description: '', + control: {type: 'select'}, + options: ['white', 'gray', 'darkGray', 'black', 'primary', 'onPrimary', 'secondary', 'onSecondary'], + }, + hasDragHandle: { + description: '드래그할 수 있는 핸들러(불주사 자국)를 켜고 끌 수 있습니다.', + control: {type: 'boolean'}, + }, + }, + args: { + backgroundColor: 'white', + children: '이건 끌 수 있는 아이템을 위한 것', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/DragHandleItem/DragHandleItem.style.ts b/HDesign/src/components/DragHandleItem/DragHandleItem.style.ts new file mode 100644 index 000000000..a08dfc574 --- /dev/null +++ b/HDesign/src/components/DragHandleItem/DragHandleItem.style.ts @@ -0,0 +1,18 @@ +import {Theme} from '@/theme/theme.type'; +import {ColorKeys} from '@/token/colors'; +import {css} from '@emotion/react'; + +export const dragHandleItemStyle = (theme: Theme, hasDragHandle: boolean, backgroundColor: ColorKeys) => + css({ + display: 'flex', + justifyContent: 'space-between', + padding: hasDragHandle ? '0.5rem 0.5rem 0.5rem 0.25rem' : '0.5rem', + borderRadius: '0.5rem', + backgroundColor: theme.colors[backgroundColor], + }); + +export const prefixStyle = css({ + display: 'flex', + gap: '0.25rem', + width: '100%', +}); diff --git a/HDesign/src/components/DragHandleItem/DragHandleItem.tsx b/HDesign/src/components/DragHandleItem/DragHandleItem.tsx new file mode 100644 index 000000000..8ae6aeb8c --- /dev/null +++ b/HDesign/src/components/DragHandleItem/DragHandleItem.tsx @@ -0,0 +1,36 @@ +/** @jsxImportSource @emotion/react */ +import React from 'react'; + +import {useTheme} from '@theme/HDesignProvider'; + +import IconButton from '../IconButton/IconButton'; +import {StrictPropsWithChildren} from '@/types/strictPropsWithChildren'; +import {dragHandleItemStyle, prefixStyle} from './DragHandleItem.style'; +import {COLORS, ColorKeys} from '@/token/colors'; + +interface DragHandleItemCustomProps { + hasDragHandle?: boolean; + backgroundColor?: ColorKeys; +} + +export type DragHandleItemProps = React.ComponentProps<'div'> & DragHandleItemCustomProps; + +export const DragHandleItem = ({ + hasDragHandle = false, + backgroundColor = 'white', + children, + ...htmlProps +}: StrictPropsWithChildren) => { + const {theme} = useTheme(); + + // TODO: (@toari) : 사람 수 많을 때 UX writing 처리 + return ( +
+
+ {hasDragHandle && } + {children} +
+
+ ); +}; +export default DragHandleItem; diff --git a/HDesign/src/components/ExpenseList/ExpenseList.stories.tsx b/HDesign/src/components/ExpenseList/ExpenseList.stories.tsx new file mode 100644 index 000000000..ccf8e28de --- /dev/null +++ b/HDesign/src/components/ExpenseList/ExpenseList.stories.tsx @@ -0,0 +1,29 @@ +/** @jsxImportSource @emotion/react */ +import type {Meta, StoryObj} from '@storybook/react'; + +import ExpenseList from '@components/ExpenseList/ExpenseList'; + +const meta = { + title: 'Components/ExpenseList', + component: ExpenseList, + tags: ['autodocs'], + argTypes: { + expenseList: { + description: '', + }, + }, + args: { + expenseList: [ + {name: '소하', price: 2000}, + {name: '토다리', price: 2000}, + {name: '웨디', price: 1080}, + {name: '쿠키', price: 3020}, + ], + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/ExpenseList/ExpenseList.style.ts b/HDesign/src/components/ExpenseList/ExpenseList.style.ts new file mode 100644 index 000000000..30d71de79 --- /dev/null +++ b/HDesign/src/components/ExpenseList/ExpenseList.style.ts @@ -0,0 +1,33 @@ +import {Theme} from '@/theme/theme.type'; +import {css} from '@emotion/react'; + +export const expenseItemStyle = () => + css({ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + width: '100%', + height: '2.5rem', + padding: '0.5rem 1rem', + }); + +export const expenseItemLeftStyle = () => + css({ + display: 'flex', + alignItems: 'center', + gap: '1rem', + }); + +export const TextStyle = (theme: Theme) => + css({ + color: theme.colors.onTertiary, + }); + +export const expenseListStyle = (theme: Theme) => + css({ + width: '100%', + backgroundColor: theme.colors.white, + padding: '0.5rem 0', + borderRadius: '1rem', + height: '100%', + }); diff --git a/HDesign/src/components/ExpenseList/ExpenseList.tsx b/HDesign/src/components/ExpenseList/ExpenseList.tsx new file mode 100644 index 000000000..0c1b8a771 --- /dev/null +++ b/HDesign/src/components/ExpenseList/ExpenseList.tsx @@ -0,0 +1,37 @@ +/** @jsxImportSource @emotion/react */ + +import {useTheme} from '@theme/HDesignProvider'; +import Text from '@components/Text/Text'; +import {Arrow} from '@assets/index'; + +import {ExpenseItemProps, ExpenseListProps} from './ExpenseList.type'; +import {expenseItemStyle, expenseListStyle, expenseItemLeftStyle, TextStyle} from './ExpenseList.style'; + +// TODO: (@soha) 따로 파일 분리할까 고민중.. 여기서만 사용할 것 같긴 한데.. 흠 +const ExpenseItem = ({name, price}: ExpenseItemProps) => { + const {theme} = useTheme(); + return ( + + ); +}; + +const ExpenseList = ({expenseList = []}: ExpenseListProps) => { + const {theme} = useTheme(); + return ( +
+ {expenseList.map(({name, price}, index: number) => ( + + ))} +
+ ); +}; + +export default ExpenseList; diff --git a/HDesign/src/components/ExpenseList/ExpenseList.type.ts b/HDesign/src/components/ExpenseList/ExpenseList.type.ts new file mode 100644 index 000000000..9ab2aa8bb --- /dev/null +++ b/HDesign/src/components/ExpenseList/ExpenseList.type.ts @@ -0,0 +1,8 @@ +export interface ExpenseItemProps { + name: string; + price: number; +} + +export type ExpenseListProps = { + expenseList: ExpenseItemProps[]; +}; diff --git a/HDesign/src/components/Flex/Flex.tsx b/HDesign/src/components/Flex/Flex.tsx new file mode 100644 index 000000000..eb2530b31 --- /dev/null +++ b/HDesign/src/components/Flex/Flex.tsx @@ -0,0 +1,39 @@ +/** @jsxImportSource @emotion/react */ +import {StrictPropsWithChildren} from '@/types/strictPropsWithChildren'; +import {changeCamelCaseToKebabCase} from '@/utils/ return str.replace(/([a-z])([A-Z])/changeCamelCaseToKebabCase'; +import {css} from '@emotion/react'; +import {FlexDirectionStrictType, FlexProps} from './Flex.type'; + +const flexStyle = ({ + justifyContent = 'flexStart', + alignItems = 'stretch', + flexDirection = 'row', + gap = '0', + padding = '0', + paddingInline = '0', + margin = '0', + width = 'auto', + height = 'auto', + ...rest +}: FlexProps) => + css({ + display: 'flex', + justifyContent: changeCamelCaseToKebabCase(justifyContent), + alignItems: changeCamelCaseToKebabCase(alignItems), + // TODO: (@weadie) as를 사용하지 않으면 방법이 없음. css의 flexDirection속성은 string을 받지 않고 명확한 속성명(ex row-reverse)를 받고 싶어함. 다만 as를 사용해도 된다고 생각한 근거는 케밥함수가 FlexDirectionType에 명시된 모든 타입을 정확하게 변환하며, 받는 문자열이 FlexDirectionType에 제한되기 때문. + flexDirection: changeCamelCaseToKebabCase(flexDirection) as FlexDirectionStrictType, + gap, + padding, + paddingInline, + margin, + width, + height, + ...rest, + }); + +// TODO: (@weadie) 지정된 프롭 말고 다른 프롭도 가져올 수 있게 하자. +const Flex = ({children, ...props}: StrictPropsWithChildren) => { + return
{children}
; +}; + +export default Flex; diff --git a/HDesign/src/components/Flex/Flex.type.ts b/HDesign/src/components/Flex/Flex.type.ts new file mode 100644 index 000000000..aeb90bc20 --- /dev/null +++ b/HDesign/src/components/Flex/Flex.type.ts @@ -0,0 +1,18 @@ +export type FlexDirectionType = 'row' | 'column' | 'rowReverse' | 'columnReverse'; +export type FlexDirectionStrictType = 'row' | 'column' | 'row-reverse' | 'column-reverse'; + +export interface FlexProps { + justifyContent?: 'flexStart' | 'center' | 'flexEnd' | 'spaceBetween' | 'spaceAround' | 'spaceEvenly'; + alignItems?: 'flexStart' | 'center' | 'flexEnd' | 'stretch' | 'baseline'; + flexDirection?: FlexDirectionType; + gap?: string; + padding?: string; + paddingInline?: string; + margin?: string; + width?: string; + height?: string; +} + +export interface ExtendedFlexProps extends FlexProps { + [key: string]: string | undefined; +} diff --git a/HDesign/src/components/InOutItem/InOutItem.stories.tsx b/HDesign/src/components/InOutItem/InOutItem.stories.tsx index 595e22b12..13ea625b5 100644 --- a/HDesign/src/components/InOutItem/InOutItem.stories.tsx +++ b/HDesign/src/components/InOutItem/InOutItem.stories.tsx @@ -12,7 +12,7 @@ const meta = { argTypes: { names: { description: '', - control: {type: 'text'}, + control: {type: 'object'}, }, inOutType: { description: '', diff --git a/HDesign/src/components/InOutItem/InOutItem.tsx b/HDesign/src/components/InOutItem/InOutItem.tsx index 97548cd40..37fd8bbd5 100644 --- a/HDesign/src/components/InOutItem/InOutItem.tsx +++ b/HDesign/src/components/InOutItem/InOutItem.tsx @@ -4,23 +4,26 @@ import React from 'react'; import {useTheme} from '@theme/HDesignProvider'; import {InOutItemProps} from './InOutItem.type'; -import {inOutItemStyle, prefixStyle, textStyle} from './InOutItem.style'; +import {prefixStyle, textStyle} from './InOutItem.style'; import Text from '@components/Text/Text'; import IconButton from '../IconButton/IconButton'; +import DragHandleItem from '../DragHandleItem/DragHandleItem'; -export const InOutItem: React.FC = ({names = [], inOutType = 'out', ...htmlProps}: InOutItemProps) => { +export const InOutItem: React.FC = ({ + names = [], + inOutType = 'out', + hasDragHandle = false, + ...htmlProps +}: InOutItemProps) => { const {theme} = useTheme(); // TODO: (@toari) : 사람 수 많을 때 UX writing 처리 return ( -
-
- - - {names.join(', ')} {inOutType === 'out' ? '나감' : '들어옴'} - -
-
+ + + {names.join(', ')} {inOutType === 'out' ? '나감' : '들어옴'} + + ); }; export default InOutItem; diff --git a/HDesign/src/components/InOutItem/InOutItem.type.ts b/HDesign/src/components/InOutItem/InOutItem.type.ts index c82fad4f8..0a7459ccc 100644 --- a/HDesign/src/components/InOutItem/InOutItem.type.ts +++ b/HDesign/src/components/InOutItem/InOutItem.type.ts @@ -5,6 +5,7 @@ export interface InOutItemStyleProps {} export interface InOutItemCustomProps { names?: string[]; inOutType?: InOutType; + hasDragHandle?: boolean; } export type InOutItemOptionProps = InOutItemStyleProps & InOutItemCustomProps; diff --git a/HDesign/src/components/Input/Input.stories.tsx b/HDesign/src/components/Input/Input.stories.tsx index da5df07ab..0f5187cb3 100644 --- a/HDesign/src/components/Input/Input.stories.tsx +++ b/HDesign/src/components/Input/Input.stories.tsx @@ -14,6 +14,10 @@ const meta = { description: '', control: {type: 'text'}, }, + inputType: { + // TODO: (@cookie) 스토리북 라디오버튼 보이도록 설정해야 함 + control: {type: 'radio'}, + }, }, args: { disabled: false, diff --git a/HDesign/src/components/Input/Input.style.ts b/HDesign/src/components/Input/Input.style.ts index b23ba358c..f45b02ea2 100644 --- a/HDesign/src/components/Input/Input.style.ts +++ b/HDesign/src/components/Input/Input.style.ts @@ -1,15 +1,29 @@ import {css} from '@emotion/react'; import {Theme} from '@theme/theme.type'; +import {InputType} from './Input.type'; -export const inputBoxStyle = (theme: Theme) => +const inputBoxBackgroundColorByInputType = (theme: Theme, inputType: InputType = 'input') => { + switch (inputType) { + case 'input': + return theme.colors.lightGrayContainer; + + case 'search': + return theme.colors.white; + + default: + return theme.colors.lightGrayContainer; + } +}; + +export const inputBoxStyle = (theme: Theme, inputType: InputType = 'input') => css({ display: 'flex', width: '100%', justifyContent: 'space-between', padding: '0.75rem 1rem', borderRadius: '1rem', - backgroundColor: theme.colors.grayContainer, + backgroundColor: inputBoxBackgroundColorByInputType(theme, inputType), }); export const inputStyle = (theme: Theme) => diff --git a/HDesign/src/components/Input/Input.tsx b/HDesign/src/components/Input/Input.tsx index 8f6c35e1e..4e8ac6e5d 100644 --- a/HDesign/src/components/Input/Input.tsx +++ b/HDesign/src/components/Input/Input.tsx @@ -9,7 +9,7 @@ import {useInput} from '@components/Input/useInput'; import {useTheme} from '@theme/HDesignProvider'; export const Input: React.FC = forwardRef(function Input( - {value: propsValue, onChange, ...htmlProps}: InputProps, + {value: propsValue, onChange, inputType, ...htmlProps}: InputProps, ref, ) { const {theme} = useTheme(); @@ -20,7 +20,7 @@ export const Input: React.FC = forwardRef +
{value && }
diff --git a/HDesign/src/components/Input/Input.type.ts b/HDesign/src/components/Input/Input.type.ts index da35ca5ed..b2f2fc827 100644 --- a/HDesign/src/components/Input/Input.type.ts +++ b/HDesign/src/components/Input/Input.type.ts @@ -4,7 +4,11 @@ export interface InputStyleProps { theme?: Theme; } -export interface InputCustomProps {} +export type InputType = 'input' | 'search'; + +export interface InputCustomProps { + inputType?: InputType; +} export type InputOptionProps = InputStyleProps & InputCustomProps; diff --git a/HDesign/src/components/StepItem/StepItem.style.ts b/HDesign/src/components/StepItem/StepItem.style.ts index a82ff00e4..0cf47c7bb 100644 --- a/HDesign/src/components/StepItem/StepItem.style.ts +++ b/HDesign/src/components/StepItem/StepItem.style.ts @@ -11,12 +11,6 @@ export const stepItemStyle = (theme: Theme) => backgroundColor: theme.colors.white, }); -export const headerStyle = css({ - display: 'flex', - justifyContent: 'space-between', - paddingInline: '0.5rem', -}); - export const nameStyle = (theme: Theme) => css({ color: theme.colors.black, @@ -28,12 +22,6 @@ export const personCountStyle = (theme: Theme) => textDecoration: 'underline', }); -export const footerStyle = css({ - display: 'flex', - justifyContent: 'space-between', - paddingInline: '0.5rem', -}); - export const totalTitleStyle = (theme: Theme) => css({ color: theme.colors.black, @@ -41,5 +29,5 @@ export const totalTitleStyle = (theme: Theme) => export const totalAmountStyle = (theme: Theme) => css({ - color: theme.colors.onSecondary, + color: theme.colors.gray, }); diff --git a/HDesign/src/components/StepItem/StepItem.tsx b/HDesign/src/components/StepItem/StepItem.tsx index 43c52fa4c..c85fe61bc 100644 --- a/HDesign/src/components/StepItem/StepItem.tsx +++ b/HDesign/src/components/StepItem/StepItem.tsx @@ -1,18 +1,11 @@ /** @jsxImportSource @emotion/react */ import {useTheme} from '@/theme/HDesignProvider'; import {StepItemCustomProps} from './StepItem.type'; -import { - footerStyle, - headerStyle, - nameStyle, - personCountStyle, - stepItemStyle, - totalAmountStyle, - totalTitleStyle, -} from './StepItem.style'; +import {nameStyle, personCountStyle, stepItemStyle, totalAmountStyle, totalTitleStyle} from './StepItem.style'; import Text from '../Text/Text'; import BillItem from '../BillItem/BillItem'; import {BillItemCustomProps} from '../BillItem/BillItem.type'; +import Flex from '../Flex/Flex'; export const StepItem: React.FC = ({ name = '', @@ -23,25 +16,25 @@ export const StepItem: React.FC = ({ const {theme} = useTheme(); return (
-
+ {name} {personCount}명 -
+ {bills.map((props: BillItemCustomProps) => ( ))} -
- + + 총액 - + {bills.reduce((acc, prev) => acc + (prev.price ?? 0), 0).toLocaleString('ko-kr')} 원 -
+
); }; diff --git a/HDesign/src/components/Switch/Switch.stories.tsx b/HDesign/src/components/Switch/Switch.stories.tsx new file mode 100644 index 000000000..121e20992 --- /dev/null +++ b/HDesign/src/components/Switch/Switch.stories.tsx @@ -0,0 +1,39 @@ +import type {Meta, StoryObj} from '@storybook/react'; + +import Switch from '@components/Switch/Switch'; + +const meta = { + title: 'Components/Switch', + component: Switch, + tags: ['autodocs'], + parameters: { + layout: 'centered', + }, + argTypes: { + value: { + description: '', + control: {type: 'select', options: ['홈', '관리']}, + }, + initialValue: { + description: '', + }, + values: { + description: '', + }, + onChange: { + description: '', + }, + }, + args: { + value: '홈', + initialValue: '홈', + values: ['홈', '관리'], + onChange: value => alert(`${value} 선택됨`), + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/Switch/Switch.style.ts b/HDesign/src/components/Switch/Switch.style.ts new file mode 100644 index 000000000..d88c18748 --- /dev/null +++ b/HDesign/src/components/Switch/Switch.style.ts @@ -0,0 +1,6 @@ +import {css} from '@emotion/react'; + +export const switchContainerStyle = css({ + display: 'flex', + gap: '0.75rem', +}); diff --git a/HDesign/src/components/Switch/Switch.tsx b/HDesign/src/components/Switch/Switch.tsx new file mode 100644 index 000000000..3ac505ff6 --- /dev/null +++ b/HDesign/src/components/Switch/Switch.tsx @@ -0,0 +1,26 @@ +/** @jsxImportSource @emotion/react */ +import TextButton from '../TextButton/TextButton'; +import {switchContainerStyle} from './Switch.style'; +import {SwitchProps} from './Switch.type'; +import {useSwitch} from './useSwitch'; + +const Switch = ({value = '', initialValue, values, onChange}: SwitchProps) => { + const {selectedValue, handleClick} = useSwitch({value, initialValue, values, onChange}); + + return ( +
+ {values.map((value, index) => ( + handleClick(index)} + > + {value} + + ))} +
+ ); +}; + +export default Switch; diff --git a/HDesign/src/components/Switch/Switch.type.ts b/HDesign/src/components/Switch/Switch.type.ts new file mode 100644 index 000000000..ec73febd0 --- /dev/null +++ b/HDesign/src/components/Switch/Switch.type.ts @@ -0,0 +1,6 @@ +export interface SwitchProps { + value?: string; + initialValue?: string; + values: string[]; + onChange: (value: string) => void; +} diff --git a/HDesign/src/components/Switch/useSwitch.ts b/HDesign/src/components/Switch/useSwitch.ts new file mode 100644 index 000000000..ecfbb0633 --- /dev/null +++ b/HDesign/src/components/Switch/useSwitch.ts @@ -0,0 +1,24 @@ +import {useEffect, useState} from 'react'; + +interface UseSwitchProps { + value: string; + initialValue?: string; + values: string[]; + onChange: (value: string) => void; +} + +export const useSwitch = ({value, initialValue, values, onChange}: UseSwitchProps) => { + const [selectedValue, setSelectedValue] = useState(initialValue ?? value); + + useEffect(() => { + setSelectedValue(value); + onChange(value); + }, [value]); + + const handleClick = (index: number) => { + setSelectedValue(values[index]); + onChange(values[index]); + }; + + return {selectedValue, handleClick}; +}; diff --git a/HDesign/src/components/Tab/Tab.stories.tsx b/HDesign/src/components/Tab/Tab.stories.tsx new file mode 100644 index 000000000..06986fec2 --- /dev/null +++ b/HDesign/src/components/Tab/Tab.stories.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import type {Meta, StoryObj} from '@storybook/react'; + +import Tab from '@components/Tab/Tab'; + +const meta = { + title: 'Components/Tab', + component: Tab, + tags: ['autodocs'], + parameters: { + // layout: 'centered', + }, + args: { + tabs: [ + {label: '전체 지출 내역', content:
없지롱
}, + {label: '참여자 별 정산', content:
있지롱
}, + ], + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/Tab/Tab.style.ts b/HDesign/src/components/Tab/Tab.style.ts new file mode 100644 index 000000000..1e8054821 --- /dev/null +++ b/HDesign/src/components/Tab/Tab.style.ts @@ -0,0 +1,51 @@ +import {Theme} from '@/theme/theme.type'; +import {css} from '@emotion/react'; + +export const tabStyle = css({ + display: 'flex', + flexDirection: 'column', + + width: '100%', +}); + +export const tabListStyle = (theme: Theme) => + css({ + display: 'flex', + position: 'relative', + justifyContent: 'space-between', + alignItems: 'center', + + padding: '0.5rem', + + borderBottomWidth: 1, + borderBottomStyle: 'solid', + borderBottomColor: theme.colors.gray, + + backgroundColor: theme.colors.white, + + cursor: 'pointer', + }); + +export const tabItemStyle = css({ + flex: 1, + + textAlign: 'center', +}); + +export const tabTextStyle = (theme: Theme, selected: boolean) => + css({ + color: selected ? theme.colors.onTertiary : theme.colors.gray, + }); + +export const indicatorStyle = (theme: Theme, leftPosition: string, tabLength: number) => + css({ + position: 'absolute', + left: leftPosition, + bottom: 0, + + width: `calc(100% / ${tabLength})`, + height: '0.125rem', + + backgroundColor: theme.colors.onSecondary, + transition: 'left 0.3s', + }); diff --git a/HDesign/src/components/Tab/Tab.tsx b/HDesign/src/components/Tab/Tab.tsx new file mode 100644 index 000000000..313f62086 --- /dev/null +++ b/HDesign/src/components/Tab/Tab.tsx @@ -0,0 +1,54 @@ +/** @jsxImportSource @emotion/react */ +import {css} from '@emotion/react'; +import React, {useState} from 'react'; + +import {useTheme} from '@theme/HDesignProvider'; + +import {tabListStyle, tabTextStyle, tabStyle, tabItemStyle, indicatorStyle} from './Tab.style'; +import {TabsProps} from './Tab.type'; +import Text from '@components/Text/Text'; + +const Tab: React.FC = ({tabs}) => { + const {theme} = useTheme(); + const [activeTabIndex, setActiveTabIndex] = useState(0); + + const isActive = (index: number) => { + return activeTabIndex === index; + }; + + return ( +
+
    + {tabs.map((tab, index) => ( + + ))} +
    +
+ {tabs.map((tab, index) => ( + + ))} +
+ ); +}; + +export default Tab; diff --git a/HDesign/src/components/Tab/Tab.type.ts b/HDesign/src/components/Tab/Tab.type.ts new file mode 100644 index 000000000..80ddd4ef9 --- /dev/null +++ b/HDesign/src/components/Tab/Tab.type.ts @@ -0,0 +1,8 @@ +export interface TabProps { + label: string; + content: React.ReactNode; +} + +export interface TabsProps { + tabs: TabProps[]; +} diff --git a/HDesign/src/components/Text/Text.style.ts b/HDesign/src/components/Text/Text.style.ts index 356f9b0a0..8767cdb0f 100644 --- a/HDesign/src/components/Text/Text.style.ts +++ b/HDesign/src/components/Text/Text.style.ts @@ -1,4 +1,4 @@ -import type {TextProps} from './Text'; +import type {TextProps} from './Text.type'; import {css} from '@emotion/react'; @@ -18,6 +18,6 @@ export const getSizeStyling = (size: Required['size']) => { caption: css(TYPOGRAPHY.caption), tiny: css(TYPOGRAPHY.tiny), }; - console.log(style[size]); + return style[size]; }; diff --git a/HDesign/src/components/Text/Text.tsx b/HDesign/src/components/Text/Text.tsx index f39428c8d..e0e2a8ec8 100644 --- a/HDesign/src/components/Text/Text.tsx +++ b/HDesign/src/components/Text/Text.tsx @@ -1,16 +1,10 @@ /** @jsxImportSource @emotion/react */ -import type {Size} from '@components/Text/Text.type'; - -import type {ComponentPropsWithoutRef} from 'react'; +import type {TextProps} from '@components/Text/Text.type'; import React from 'react'; import {getSizeStyling} from './Text.style'; -export interface TextProps extends ComponentPropsWithoutRef<'p'> { - size?: Size | 'bodyBold' | 'smallBodyBold' | 'captionBold'; -} - const Text: React.FC = ({size = 'body', children, ...attributes}: TextProps) => { return (

diff --git a/HDesign/src/components/Text/Text.type.ts b/HDesign/src/components/Text/Text.type.ts index d27b9b61b..db75b09be 100644 --- a/HDesign/src/components/Text/Text.type.ts +++ b/HDesign/src/components/Text/Text.type.ts @@ -1 +1,21 @@ -export type Size = 'head' | 'title' | 'subTitle' | 'body' | 'smallBody' | 'caption' | 'tiny'; +export type TextSize = + | 'head' + | 'title' + | 'subTitle' + | 'body' + | 'smallBody' + | 'caption' + | 'tiny' + | 'bodyBold' + | 'smallBodyBold' + | 'captionBold'; + +export interface TextStyleProps { + size?: TextSize; +} + +export interface TextCustomProps {} + +export type TextOptionProps = TextStyleProps & TextCustomProps; + +export type TextProps = React.ComponentProps<'p'> & TextOptionProps; diff --git a/HDesign/src/components/TextButton/TextButton.stories.tsx b/HDesign/src/components/TextButton/TextButton.stories.tsx new file mode 100644 index 000000000..9873df3f4 --- /dev/null +++ b/HDesign/src/components/TextButton/TextButton.stories.tsx @@ -0,0 +1,50 @@ +import type {Meta, StoryObj} from '@storybook/react'; + +import TextButton from '@components/TextButton/TextButton'; + +const meta = { + title: 'Components/TextButton', + component: TextButton, + tags: ['autodocs'], + parameters: { + layout: 'centered', + }, + argTypes: { + textSize: { + description: '', + control: {type: 'select'}, + options: [ + 'head', + 'title', + 'subTitle', + 'bodyBold', + 'body', + 'smallBodyBold', + 'smallBody', + 'caption', + 'captionBold', + 'tiny', + ], + }, + textColor: { + description: '', + control: {type: 'select'}, + options: ['black', 'gray'], + }, + children: { + description: '', + control: {type: 'text'}, + }, + }, + args: { + textColor: 'black', + textSize: 'bodyBold', + children: '뒤로가기', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/TextButton/TextButton.style.ts b/HDesign/src/components/TextButton/TextButton.style.ts new file mode 100644 index 000000000..e2b602c62 --- /dev/null +++ b/HDesign/src/components/TextButton/TextButton.style.ts @@ -0,0 +1,13 @@ +import {Theme} from '@/theme/theme.type'; +import {TextColor} from './TextButton.type'; +import {css} from '@emotion/react'; + +interface TextButtonStyleProps { + textColor: TextColor; + theme: Theme; +} + +export const textButtonStyle = ({textColor, theme}: TextButtonStyleProps) => + css({ + color: theme.colors[textColor], + }); diff --git a/HDesign/src/components/TextButton/TextButton.tsx b/HDesign/src/components/TextButton/TextButton.tsx new file mode 100644 index 000000000..c44b7a5c7 --- /dev/null +++ b/HDesign/src/components/TextButton/TextButton.tsx @@ -0,0 +1,23 @@ +/** @jsxImportSource @emotion/react */ +import {forwardRef} from 'react'; +import {TextButtonProps} from './TextButton.type'; +import Text from '../Text/Text'; +import {useTheme} from '@/theme/HDesignProvider'; +import {textButtonStyle} from './TextButton.style'; + +export const TextButton: React.FC = forwardRef(function Button( + {textColor, textSize, children, ...htmlProps}: TextButtonProps, + ref, +) { + const {theme} = useTheme(); + + return ( + + ); +}); + +export default TextButton; diff --git a/HDesign/src/components/TextButton/TextButton.type.ts b/HDesign/src/components/TextButton/TextButton.type.ts new file mode 100644 index 000000000..0299d89b9 --- /dev/null +++ b/HDesign/src/components/TextButton/TextButton.type.ts @@ -0,0 +1,15 @@ +import {TextSize} from '../Text/Text.type'; + +export type TextColor = 'black' | 'gray'; + +export interface TextButtonStyleProps { + textColor: TextColor; +} + +export interface TextButtonCustomProps { + textSize: TextSize; +} + +export type TextButtonOptionProps = TextButtonStyleProps & TextButtonCustomProps; + +export type TextButtonProps = React.ComponentProps<'button'> & TextButtonOptionProps; diff --git a/HDesign/src/components/Title/Title.stories.tsx b/HDesign/src/components/Title/Title.stories.tsx index 0b650b280..3973779db 100644 --- a/HDesign/src/components/Title/Title.stories.tsx +++ b/HDesign/src/components/Title/Title.stories.tsx @@ -18,10 +18,15 @@ const meta = { description: '', control: {type: 'text'}, }, + price: { + description: '', + control: {type: 'number'}, + }, }, args: { title: '페이지 제목이에요', description: '이곳에는 페이지 설명이 들어가요. 페이지에 대한 설명을 자세하게 적어주면 좋아요 :)', + price: 100000, }, } satisfies Meta; diff --git a/HDesign/src/components/Title/Title.style.ts b/HDesign/src/components/Title/Title.style.ts index 2b298d2cf..ca0a02fc3 100644 --- a/HDesign/src/components/Title/Title.style.ts +++ b/HDesign/src/components/Title/Title.style.ts @@ -2,13 +2,14 @@ import {css} from '@emotion/react'; import {Theme} from '@theme/theme.type'; -export const titleContainerStyle = css({ - display: 'flex', - flexDirection: 'column', - gap: '0.5rem', - - padding: '0 1rem', -}); +export const titleContainerStyle = (theme: Theme) => + css({ + display: 'flex', + flexDirection: 'column', + gap: '0.5rem', + backgroundColor: theme.colors.white, + padding: '1rem', + }); export const titleStyle = (theme: Theme) => css({ @@ -19,3 +20,19 @@ export const descriptionStyle = (theme: Theme) => css({ color: theme.colors.darkGray, }); + +export const priceContainerStyle = css({ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'end', +}); + +export const priceTitleStyle = (theme: Theme) => + css({ + color: theme.colors.gray, + }); + +export const priceStyle = (theme: Theme) => + css({ + color: theme.colors.black, + }); diff --git a/HDesign/src/components/Title/Title.tsx b/HDesign/src/components/Title/Title.tsx index 556c037e4..5901bc350 100644 --- a/HDesign/src/components/Title/Title.tsx +++ b/HDesign/src/components/Title/Title.tsx @@ -1,18 +1,37 @@ /** @jsxImportSource @emotion/react */ import Text from '@components/Text/Text'; -import {descriptionStyle, titleContainerStyle, titleStyle} from '@components/Title/Title.style'; +import { + descriptionStyle, + priceContainerStyle, + priceStyle, + priceTitleStyle, + titleContainerStyle, + titleStyle, +} from '@components/Title/Title.style'; import {TitleProps} from '@components/Title/Title.type'; import {useTheme} from '@theme/HDesignProvider'; -export const Title: React.FC = ({title, description}: TitleProps) => { +export const Title: React.FC = ({title, description, price}: TitleProps) => { const {theme} = useTheme(); return ( -

+
{title} - {description} + {description && ( + + {description} + + )} + {price && ( +
+ + 전체 지출 금액 + + {price.toLocaleString('ko-kr')} 원 +
+ )}
); }; diff --git a/HDesign/src/components/Title/Title.type.ts b/HDesign/src/components/Title/Title.type.ts index fa3fb4e3f..4b12f23b2 100644 --- a/HDesign/src/components/Title/Title.type.ts +++ b/HDesign/src/components/Title/Title.type.ts @@ -3,6 +3,7 @@ export interface TitleStyleProps {} export interface TitleCustomProps { title: string; description?: string; + price?: number; } export type TitleOptionProps = TitleStyleProps & TitleCustomProps; diff --git a/HDesign/src/components/TopNav/TopNav.stories.ts b/HDesign/src/components/TopNav/TopNav.stories.ts new file mode 100644 index 000000000..f37845346 --- /dev/null +++ b/HDesign/src/components/TopNav/TopNav.stories.ts @@ -0,0 +1,28 @@ +import type {Meta, StoryObj} from '@storybook/react'; + +import TopNav from '@components/TopNav/TopNav'; +import Switch from '../Switch/Switch'; + +const meta = { + title: 'Components/TopNav', + component: TopNav, + tags: ['autodocs'], + parameters: { + layout: 'centered', + }, + argTypes: { + navType: { + description: '', + control: {type: 'select', options: ['back', 'home']}, + }, + }, + args: { + navType: 'back', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/TopNav/TopNav.style.ts b/HDesign/src/components/TopNav/TopNav.style.ts new file mode 100644 index 000000000..cd4244eb3 --- /dev/null +++ b/HDesign/src/components/TopNav/TopNav.style.ts @@ -0,0 +1,6 @@ +import {css} from '@emotion/react'; + +export const topNavStyle = css({ + display: 'flex', + padding: '0 1rem', +}); diff --git a/HDesign/src/components/TopNav/TopNav.tsx b/HDesign/src/components/TopNav/TopNav.tsx new file mode 100644 index 000000000..75ce368ff --- /dev/null +++ b/HDesign/src/components/TopNav/TopNav.tsx @@ -0,0 +1,24 @@ +import {useNavigate} from 'react-router-dom'; +import TextButton from '../TextButton/TextButton'; +import {topNavStyle} from './TopNav.style'; +import {TopNavProps} from './TopNav.type'; +import Switch from '../Switch/Switch'; + +// TODO: (@todari) navigation으로 인해 storybook 동작하지 않는 오류 해결해야함 +// + 페이지 정하는 것에 따라, navigate 경로 수정해 줘야 함 +const TopNav = ({navType}: TopNavProps) => { + const navigate = useNavigate(); + return ( +
+ {navType === 'back' ? ( + navigate(-1)} textSize="bodyBold" textColor="gray"> + 뒤로가기 + + ) : ( + navigate('./')}> + )} +
+ ); +}; + +export default TopNav; diff --git a/HDesign/src/components/TopNav/TopNav.type.ts b/HDesign/src/components/TopNav/TopNav.type.ts new file mode 100644 index 000000000..c84e21894 --- /dev/null +++ b/HDesign/src/components/TopNav/TopNav.type.ts @@ -0,0 +1,5 @@ +type NavType = 'back' | 'home'; + +export interface TopNavProps { + navType: NavType; +} diff --git a/HDesign/src/token/colors.ts b/HDesign/src/token/colors.ts index 73f7b4f7f..01bbf8f02 100644 --- a/HDesign/src/token/colors.ts +++ b/HDesign/src/token/colors.ts @@ -28,7 +28,20 @@ const PRIMITIVE_COLORS = { type Color = string; -export type ColorTokens = Record; +export type ColorKeys = + | 'white' + | 'gray' + | 'darkGray' + | 'black' + | 'primary' + | 'onPrimary' + | 'secondary' + | 'onSecondary' + | 'tertiary' + | 'onTertiary' + | 'grayContainer' + | 'lightGrayContainer'; +export type ColorTokens = Record; // TODO: (@soha) 대괄호 사용에 대해 논의 export const COLORS: ColorTokens = { diff --git a/HDesign/src/types/strictPropsWithChildren.ts b/HDesign/src/types/strictPropsWithChildren.ts new file mode 100644 index 000000000..684fbcc76 --- /dev/null +++ b/HDesign/src/types/strictPropsWithChildren.ts @@ -0,0 +1,3 @@ +export type StrictPropsWithChildren

= P & { + children: React.ReactNode; +}; diff --git a/HDesign/src/utils/ return str.replace(/([a-z])([A-Z])/changeCamelCaseToKebabCase.ts b/HDesign/src/utils/ return str.replace(/([a-z])([A-Z])/changeCamelCaseToKebabCase.ts new file mode 100644 index 000000000..2bca7c1b7 --- /dev/null +++ b/HDesign/src/utils/ return str.replace(/([a-z])([A-Z])/changeCamelCaseToKebabCase.ts @@ -0,0 +1,3 @@ +export const changeCamelCaseToKebabCase = (str: string) => { + return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); +}; From 9c22e4724b2029f1a43726ca1452faed357627d5 Mon Sep 17 00:00:00 2001 From: juha Date: Fri, 19 Jul 2024 17:56:45 +0900 Subject: [PATCH 054/178] =?UTF-8?q?refactor:=20BillAction=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/haengdong/domain/BillAction.java | 24 +++++++- .../haengdong/domain/BillActionTest.java | 56 +++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 server/src/test/java/server/haengdong/domain/BillActionTest.java diff --git a/server/src/main/java/server/haengdong/domain/BillAction.java b/server/src/main/java/server/haengdong/domain/BillAction.java index 24ab5a410..3253a3edb 100644 --- a/server/src/main/java/server/haengdong/domain/BillAction.java +++ b/server/src/main/java/server/haengdong/domain/BillAction.java @@ -1,6 +1,7 @@ package server.haengdong.domain; import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; @@ -16,6 +17,11 @@ @Entity public class BillAction { + private static final int MIN_TITLE_LENGTH = 2; + private static final int MAX_TITLE_LENGTH = 30; + private static final long MIN_PRICE = 1L; + private static final long MAX_PRICE = 10_000_000L; + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @@ -23,16 +29,32 @@ public class BillAction { @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) private Action action; + @Column(length = MAX_TITLE_LENGTH) private String title; private Long price; public BillAction(Action action, String title, Long price) { + validateTitle(title); + validatePrice(price); this.action = action; - this.title = title; + this.title = title.trim(); this.price = price; } + private void validateTitle(String title) { + int titleLength = title.trim().length(); + if (titleLength < MIN_TITLE_LENGTH || titleLength > MAX_TITLE_LENGTH) { + throw new IllegalArgumentException("앞뒤 공백을 제거한 지출 내역 제목은 2 ~ 30자여야 합니다."); + } + } + + private void validatePrice(Long price) { + if (price < MIN_PRICE || price > MAX_PRICE) { + throw new IllegalArgumentException("지출 금액은 10,000,000 이하의 자연수여야 합니다."); + } + } + public Long getSequence() { return action.getSequence(); } diff --git a/server/src/test/java/server/haengdong/domain/BillActionTest.java b/server/src/test/java/server/haengdong/domain/BillActionTest.java new file mode 100644 index 000000000..93160a114 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/BillActionTest.java @@ -0,0 +1,56 @@ +package server.haengdong.domain; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class BillActionTest { + + @DisplayName("앞뒤 공백을 제거한 title이 2 ~ 30자가 아니면 지출을 생성할 수 없다.") + @ParameterizedTest + @ValueSource(strings = {" 감 ", "", " ", "감자감자감자감자감자감자백호백호백호백호백호감자감자감자감자감자감자백호백호백호백호백호"}) + void validateTitle(String title) { + Event event = new Event("name", "token"); + Action action = new Action(event, 1L); + Long price = 100L; + + assertThatThrownBy(() -> new BillAction(action, title, price)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("앞뒤 공백을 제거한 지출 내역 제목은 2 ~ 30자여야 합니다."); + } + + @DisplayName("금액이 10,000,000 이하의 자연수가 아니면 지출을 생성할 수 없다.") + @ParameterizedTest + @ValueSource(longs = {0, 10_000_001, 20_000_000}) + void validatePrice(long price) { + Event event = new Event("name", "token"); + Action action = new Action(event, 1L); + String title = "title"; + + assertThatThrownBy(() -> new BillAction(action, title, price)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("지출 금액은 10,000,000 이하의 자연수여야 합니다."); + } + + @DisplayName("지출 내역을 올바르게 생성한다.") + @Test + void createBillAction() { + Event event = new Event("name", "token"); + Action action = new Action(event, 1L); + String title = "title"; + Long price = 1_000L; + + BillAction billAction = new BillAction(action, title, price); + + assertAll( + () -> assertThat(billAction.getAction()).isEqualTo(action), + () -> assertThat(billAction.getTitle()).isEqualTo(title), + () -> assertThat(billAction.getPrice()).isEqualTo(price) + ); + } +} From 24ef6e4ad0f333d534eac1fdc2c8f4bac2d6ce17 Mon Sep 17 00:00:00 2001 From: Arachneee Date: Sat, 20 Jul 2024 00:56:53 +0900 Subject: [PATCH 055/178] =?UTF-8?q?refactor:=20=EC=A7=80=EC=B6=9C=20?= =?UTF-8?q?=EB=82=B4=EC=97=AD=20=EC=B6=94=EA=B0=80=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/BillActionService.java | 15 ++++------ .../java/server/haengdong/domain/Action.java | 10 +++++++ .../server/haengdong/domain/ActionTest.java | 29 +++++++++++++++++++ 3 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 server/src/test/java/server/haengdong/domain/ActionTest.java diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java index 6c69e383f..0c62c133f 100644 --- a/server/src/main/java/server/haengdong/application/BillActionService.java +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -1,6 +1,5 @@ package server.haengdong.application; -import java.util.ArrayList; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -26,20 +25,18 @@ public class BillActionService { public void saveAllBillAction(String eventToken, List requests) { Event event = eventRepository.findByToken(eventToken) .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 이벤트 토큰입니다.")); - long lastSequence = getLastSequence(event); + Action action = createStartAction(event); - List billActions = new ArrayList<>(); for (BillActionAppRequest request : requests) { - Action action = new Action(event, ++lastSequence); BillAction billAction = request.toBillAction(action); - billActions.add(billAction); + billActionRepository.save(billAction); + action = action.next(); } - billActionRepository.saveAll(billActions); } - private long getLastSequence(Event event) { + private Action createStartAction(Event event) { return actionRepository.findLastByEvent(event) - .map(Action::getSequence) - .orElse(0L); + .map(Action::next) + .orElse(Action.createFirst(event)); } } diff --git a/server/src/main/java/server/haengdong/domain/Action.java b/server/src/main/java/server/haengdong/domain/Action.java index 7a47b1de5..be294dac3 100644 --- a/server/src/main/java/server/haengdong/domain/Action.java +++ b/server/src/main/java/server/haengdong/domain/Action.java @@ -15,6 +15,8 @@ @Entity public class Action { + private static final long FIRST_SEQUENCE = 1L; + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @@ -28,4 +30,12 @@ public Action(Event event, Long sequence) { this.event = event; this.sequence = sequence; } + + public static Action createFirst(Event event) { + return new Action(event, FIRST_SEQUENCE); + } + + public Action next() { + return new Action(event, sequence + 1); + } } diff --git a/server/src/test/java/server/haengdong/domain/ActionTest.java b/server/src/test/java/server/haengdong/domain/ActionTest.java new file mode 100644 index 000000000..a699fb04a --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/ActionTest.java @@ -0,0 +1,29 @@ +package server.haengdong.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class ActionTest { + + @DisplayName("액션의 초기 순서번호는 1이다.") + @Test + void createFirst() { + Event event = new Event("name", "token"); + Action action = Action.createFirst(event); + + assertThat(action.getSequence()).isOne(); + } + + @DisplayName("현재 액션의 다음 액션의 순서는 1만큼 증가한다.") + @Test + void next() { + Event event = new Event("name", "token"); + Action action = new Action(event, 2L); + + Action nextAction = action.next(); + + assertThat(nextAction.getSequence()).isEqualTo(3L); + } +} From ef63c604188db4b1d035f7570ba3a2fdd9871d51 Mon Sep 17 00:00:00 2001 From: Arachneee Date: Sun, 21 Jul 2024 00:30:02 +0900 Subject: [PATCH 056/178] =?UTF-8?q?feat:=20BillAction=EA=B3=BC=20Action=20?= =?UTF-8?q?cascade=20=EC=98=B5=EC=85=98=EA=B3=BC=20orphanRemoval=20?= =?UTF-8?q?=EC=98=B5=EC=85=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/main/java/server/haengdong/domain/BillAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/server/haengdong/domain/BillAction.java b/server/src/main/java/server/haengdong/domain/BillAction.java index 3253a3edb..557715e4b 100644 --- a/server/src/main/java/server/haengdong/domain/BillAction.java +++ b/server/src/main/java/server/haengdong/domain/BillAction.java @@ -26,7 +26,7 @@ public class BillAction { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) private Action action; @Column(length = MAX_TITLE_LENGTH) From fd926b6d9ecd8192e19c38b33c48687d08f5943a Mon Sep 17 00:00:00 2001 From: Arachneee Date: Sun, 21 Jul 2024 00:31:20 +0900 Subject: [PATCH 057/178] =?UTF-8?q?test:=20event=20save=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/haengdong/application/BillActionServiceTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java index ba0cfc41a..cae27b94b 100644 --- a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java @@ -32,7 +32,8 @@ class BillActionServiceTest { @Test void saveAllBillAction() { String token = "TOKEN"; - Event event = eventRepository.save(new Event("감자", token)); + Event event = new Event("감자", token); + Event savedEvent = eventRepository.save(event); List requests = List.of( new BillActionAppRequest("뽕족", 10_000L), @@ -41,7 +42,7 @@ void saveAllBillAction() { billActionService.saveAllBillAction(token, requests); - List actions = billActionRepository.findByAction_Event(event) + List actions = billActionRepository.findByAction_Event(savedEvent) .stream() .sorted(Comparator.comparing(BillAction::getSequence).reversed()) .limit(requests.size()) From 926ef4060bc2b0b4f7884449c3252ea6a4559320 Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Sun, 21 Jul 2024 08:24:15 +0900 Subject: [PATCH 058/178] =?UTF-8?q?test:=20DisplayName=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Juhwan Kim <13selfesteem91@naver.com> --- .../src/test/java/server/haengdong/domain/BillActionTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/test/java/server/haengdong/domain/BillActionTest.java b/server/src/test/java/server/haengdong/domain/BillActionTest.java index 93160a114..d5d8132fe 100644 --- a/server/src/test/java/server/haengdong/domain/BillActionTest.java +++ b/server/src/test/java/server/haengdong/domain/BillActionTest.java @@ -11,7 +11,7 @@ class BillActionTest { - @DisplayName("앞뒤 공백을 제거한 title이 2 ~ 30자가 아니면 지출을 생성할 수 없다.") + @DisplayName("지출 내역 제목의 앞뒤 공백을 제거한 길이가 2 ~ 30자가 아니면 지출을 생성할 수 없다.") @ParameterizedTest @ValueSource(strings = {" 감 ", "", " ", "감자감자감자감자감자감자백호백호백호백호백호감자감자감자감자감자감자백호백호백호백호백호"}) void validateTitle(String title) { From 507676e2fcb07df4bf64be4783609f21ff13676e Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Sun, 21 Jul 2024 08:24:42 +0900 Subject: [PATCH 059/178] =?UTF-8?q?test:=20=EA=B2=BD=EA=B3=84=EA=B0=92=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Juhwan Kim <13selfesteem91@naver.com> --- .../src/test/java/server/haengdong/domain/BillActionTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/test/java/server/haengdong/domain/BillActionTest.java b/server/src/test/java/server/haengdong/domain/BillActionTest.java index d5d8132fe..5789f8c94 100644 --- a/server/src/test/java/server/haengdong/domain/BillActionTest.java +++ b/server/src/test/java/server/haengdong/domain/BillActionTest.java @@ -13,7 +13,7 @@ class BillActionTest { @DisplayName("지출 내역 제목의 앞뒤 공백을 제거한 길이가 2 ~ 30자가 아니면 지출을 생성할 수 없다.") @ParameterizedTest - @ValueSource(strings = {" 감 ", "", " ", "감자감자감자감자감자감자백호백호백호백호백호감자감자감자감자감자감자백호백호백호백호백호"}) + @ValueSource(strings = {" 감 ", "", " ", "1234567890123456789012345678901"}) void validateTitle(String title) { Event event = new Event("name", "token"); Action action = new Action(event, 1L); From a91426aa7a57502b94dbe307ab1f2c84e53fcccc Mon Sep 17 00:00:00 2001 From: JUHA <84626225+khabh@users.noreply.github.com> Date: Sun, 21 Jul 2024 10:59:07 +0900 Subject: [PATCH 060/178] =?UTF-8?q?test:=20=EC=A7=80=EC=B6=9C=20=EB=82=B4?= =?UTF-8?q?=EC=97=AD=20=EC=83=9D=EC=84=B1=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/BillActionServiceTest.java | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java index cae27b94b..df19b9e63 100644 --- a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java @@ -4,7 +4,6 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.tuple; -import java.util.Comparator; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -42,16 +41,12 @@ void saveAllBillAction() { billActionService.saveAllBillAction(token, requests); - List actions = billActionRepository.findByAction_Event(savedEvent) - .stream() - .sorted(Comparator.comparing(BillAction::getSequence).reversed()) - .limit(requests.size()) - .toList(); + List actions = billActionRepository.findByAction_Event(savedEvent); - assertThat(actions).extracting("title", "price") - .containsExactly( - tuple("인생맥주", 15_000L), - tuple("뽕족", 10_000L) + assertThat(actions).extracting(BillAction::getTitle, BillAction::getPrice, BillAction::getSequence) + .containsExactlyInAnyOrder( + tuple("뽕족", 10_000L, 1L), + tuple("인생맥주", 15_000L, 2L) ); } From 2b5345d4332bb3e2dad531858c1b46778abf3729 Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Sun, 21 Jul 2024 13:22:55 +0900 Subject: [PATCH 061/178] =?UTF-8?q?feat:=20PR=20=ED=9B=84=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EB=A6=AC=ED=8F=AC=ED=8A=B8=20=EB=B0=9C?= =?UTF-8?q?=ED=96=89=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20(#56)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/backend-pull-request.yml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/workflows/backend-pull-request.yml b/.github/workflows/backend-pull-request.yml index a5cfbfda7..113972929 100644 --- a/.github/workflows/backend-pull-request.yml +++ b/.github/workflows/backend-pull-request.yml @@ -14,9 +14,6 @@ jobs: run: working-directory: ./server - permissions: - contents: read - steps: - name: CheckOut uses: actions/checkout@v4 @@ -32,3 +29,15 @@ jobs: - name: Test with Gradle Wrapper run: ./gradlew clean build + + - name: publish unit test results + uses: EnricoMi/publish-unit-test-result-action@v2 + if: always() + with: + files: server/build/test-results/test/TEST-*.xml + + - name: add comments to a pull request + uses: mikepenz/action-junit-report@v3 + if: always() + with: + report_paths: server/build/test-results/test/TEST-*.xml From e489d8230d2b271489a272fab5377f445dc732b0 Mon Sep 17 00:00:00 2001 From: Arachneee Date: Sun, 21 Jul 2024 13:30:29 +0900 Subject: [PATCH 062/178] =?UTF-8?q?test:=20=EB=AF=B8=EC=82=AC=EC=9A=A9=20t?= =?UTF-8?q?est=20class=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/haengdong/ServerApplicationTests.java | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 server/src/test/java/server/haengdong/ServerApplicationTests.java diff --git a/server/src/test/java/server/haengdong/ServerApplicationTests.java b/server/src/test/java/server/haengdong/ServerApplicationTests.java deleted file mode 100644 index d4bf7167e..000000000 --- a/server/src/test/java/server/haengdong/ServerApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package server.haengdong; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class ServerApplicationTests { - - @Test - void contextLoads() { - } - -} From 7dc4e8f0c925c9effce3be72eb1a2646166b3b1e Mon Sep 17 00:00:00 2001 From: Juhwan Kim <13selfesteem91@naver.com> Date: Sun, 21 Jul 2024 15:32:09 +0900 Subject: [PATCH 063/178] =?UTF-8?q?[BE]=20=EC=9D=B8=EC=9B=90=20=EB=B3=80?= =?UTF-8?q?=EB=8F=99=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20=20(#47)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 인원 변동 기능 구현 Co-authored-by: kunsanglee * refactor: 메서드 분리 Co-authored-by: kunsanglee * refactor: 코드 컨벤션 Co-authored-by: kunsanglee * refactor: 멤버 액션 생성 클래스 분리 Co-authored-by: kunsanglee * refactor: MemberActionFactory 코드 리팩터링 * refactor: DTO 클래스명 리팩터링 * refactor: MemberActionRepository Lazy Loading 적용 * test: MemberActionFactory createMemberActions 결과 검증 테스트 추가 * refactor: 컨벤션에 맞게 수정 Co-authored-by: kunsanglee * refactor: memberActions를 복사해서 내림차순 정렬하도록 수정, 검증 로직 내부로 이동 Co-authored-by: kunsanglee Co-authored-by: Arachne * refactor: memberActions를 복사해서 내림차순 정렬하도록 수정, 검증 로직 내부로 이동 * refactor: 컨벤션에 맞게 수정 * feat: 사용자 이름이 중복 입력되는 예외 상황 검증 Co-authored-by: kunsanglee Co-authored-by: Arachne * refactor: 메서드 순서 변경 Co-authored-by: Arachne --------- Co-authored-by: kunsanglee Co-authored-by: Arachne authored-by: khabh --- .../application/MemberActionFactory.java | 80 +++++++ .../application/MemberActionService.java | 41 ++++ .../request/MemberActionSaveAppRequest.java | 12 + .../request/MemberActionsSaveAppRequest.java | 6 + .../server/haengdong/domain/EventStep.java | 2 +- .../server/haengdong/domain/MemberAction.java | 22 +- .../haengdong/domain/MemberActionStatus.java | 9 + .../domain/MemberGroupIdProvider.java | 11 + .../persistence/ActionRepository.java | 3 +- .../persistence/EventRepository.java | 2 +- .../persistence/MemberActionRepository.java | 16 ++ .../presentation/MemberActionController.java | 27 +++ .../request/MemberActionSaveRequest.java | 10 + .../request/MemberActionsSaveRequest.java | 16 ++ .../application/MemberActionFactoryTest.java | 216 ++++++++++++++++++ .../application/MemberActionServiceTest.java | 82 +++++++ .../presentation/EventControllerTest.java | 4 +- .../MemberActionControllerTest.java | 49 ++++ 18 files changed, 602 insertions(+), 6 deletions(-) create mode 100644 server/src/main/java/server/haengdong/application/MemberActionFactory.java create mode 100644 server/src/main/java/server/haengdong/application/MemberActionService.java create mode 100644 server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java create mode 100644 server/src/main/java/server/haengdong/domain/MemberGroupIdProvider.java create mode 100644 server/src/main/java/server/haengdong/persistence/MemberActionRepository.java create mode 100644 server/src/main/java/server/haengdong/presentation/MemberActionController.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/MemberActionSaveRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java create mode 100644 server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java create mode 100644 server/src/test/java/server/haengdong/application/MemberActionServiceTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java diff --git a/server/src/main/java/server/haengdong/application/MemberActionFactory.java b/server/src/main/java/server/haengdong/application/MemberActionFactory.java new file mode 100644 index 000000000..d583967a0 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/MemberActionFactory.java @@ -0,0 +1,80 @@ +package server.haengdong.application; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.domain.Action; +import server.haengdong.domain.MemberAction; +import server.haengdong.domain.MemberActionStatus; +import server.haengdong.domain.MemberGroupIdProvider; + +@RequiredArgsConstructor +@Component +public class MemberActionFactory { + + private final MemberGroupIdProvider memberGroupIdProvider; + + public List createMemberActions( + MemberActionsSaveAppRequest request, + List memberActions, + Action action + ) { + validateMemberNames(request); + validateActions(request, memberActions); + + Long memberGroupId = memberGroupIdProvider.createGroupId(); + List createdMemberActions = new ArrayList<>(); + List actions = request.actions(); + for (MemberActionSaveAppRequest appRequest : actions) { + MemberAction memberAction = appRequest.toMemberAction(action, memberGroupId); + createdMemberActions.add(memberAction); + action = action.next(); + } + + return createdMemberActions; + } + + private void validateMemberNames(MemberActionsSaveAppRequest request) { + List memberNames = request.actions().stream() + .map(MemberActionSaveAppRequest::name) + .toList(); + + long uniqueCount = memberNames.stream().distinct().count(); + if (uniqueCount != memberNames.size()) { + throw new IllegalArgumentException(); + } + } + + private void validateActions(MemberActionsSaveAppRequest request, List memberActions) { + List reverseSortedMemberActions = memberActions.stream() + .sorted(Comparator.comparing(MemberAction::getSequence).reversed()) + .toList(); + + for (MemberActionSaveAppRequest action : request.actions()) { + validateAction(action, reverseSortedMemberActions); + } + } + + private void validateAction(MemberActionSaveAppRequest request, List memberActions) { + MemberActionStatus memberActionStatus = MemberActionStatus.of(request.status()); + if (isInvalidStatus(memberActions, request.name(), memberActionStatus)) { + throw new IllegalArgumentException(); + } + } + + private boolean isInvalidStatus( + List memberActions, + String memberName, + MemberActionStatus memberActionStatus + ) { + return memberActions.stream() + .filter(action -> action.isSameName(memberName)) + .findFirst() + .map(action -> action.isSameStatus(memberActionStatus)) + .orElse(MemberActionStatus.IN != memberActionStatus); + } +} diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java new file mode 100644 index 000000000..491981b06 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -0,0 +1,41 @@ +package server.haengdong.application; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.domain.Action; +import server.haengdong.domain.Event; +import server.haengdong.domain.MemberAction; +import server.haengdong.persistence.ActionRepository; +import server.haengdong.persistence.EventRepository; +import server.haengdong.persistence.MemberActionRepository; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class MemberActionService { + + private final MemberActionFactory memberActionFactory; + private final MemberActionRepository memberActionRepository; + private final EventRepository eventRepository; + private final ActionRepository actionRepository; + + @Transactional + public void saveMemberAction(String token, MemberActionsSaveAppRequest request) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new IllegalArgumentException("event not found")); + + List findMemberActions = memberActionRepository.findAllByEvent(event); + Action action = createStartAction(event); + List memberActions = memberActionFactory.createMemberActions(request, findMemberActions, action); + memberActionRepository.saveAll(memberActions); + } + + private Action createStartAction(Event event) { + return actionRepository.findLastByEvent(event) + .map(Action::next) + .orElse(Action.createFirst(event)); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java new file mode 100644 index 000000000..a7c90efe4 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java @@ -0,0 +1,12 @@ +package server.haengdong.application.request; + +import server.haengdong.domain.Action; +import server.haengdong.domain.MemberAction; +import server.haengdong.domain.MemberActionStatus; + +public record MemberActionSaveAppRequest(String name, String status) { + + public MemberAction toMemberAction(Action action, Long memberGroupId) { + return new MemberAction(action, name, MemberActionStatus.of(status), memberGroupId); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java new file mode 100644 index 000000000..650b908df --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java @@ -0,0 +1,6 @@ +package server.haengdong.application.request; + +import java.util.List; + +public record MemberActionsSaveAppRequest(List actions) { +} diff --git a/server/src/main/java/server/haengdong/domain/EventStep.java b/server/src/main/java/server/haengdong/domain/EventStep.java index 741dcaba5..b25035fa5 100644 --- a/server/src/main/java/server/haengdong/domain/EventStep.java +++ b/server/src/main/java/server/haengdong/domain/EventStep.java @@ -21,7 +21,7 @@ public class EventStep { @ManyToOne(fetch = FetchType.LAZY) private Event event; - + private String name; private Long sequence; diff --git a/server/src/main/java/server/haengdong/domain/MemberAction.java b/server/src/main/java/server/haengdong/domain/MemberAction.java index 6d8ea9b20..eb8d8fdec 100644 --- a/server/src/main/java/server/haengdong/domain/MemberAction.java +++ b/server/src/main/java/server/haengdong/domain/MemberAction.java @@ -1,5 +1,6 @@ package server.haengdong.domain; +import jakarta.persistence.CascadeType; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; @@ -21,7 +22,7 @@ public class MemberAction { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @OneToOne(fetch = FetchType.LAZY) + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) private Action action; private String memberName; @@ -30,4 +31,23 @@ public class MemberAction { private MemberActionStatus status; private Long memberGroupId; + + public MemberAction(Action action, String memberName, MemberActionStatus status, Long memberGroupId) { + this.action = action; + this.memberName = memberName; + this.status = status; + this.memberGroupId = memberGroupId; + } + + public boolean isSameName(String name) { + return memberName.equals(name); + } + + public boolean isSameStatus(MemberActionStatus memberActionStatus) { + return status == memberActionStatus; + } + + public Long getSequence() { + return action.getSequence(); + } } diff --git a/server/src/main/java/server/haengdong/domain/MemberActionStatus.java b/server/src/main/java/server/haengdong/domain/MemberActionStatus.java index af7fad121..6172bdb4d 100644 --- a/server/src/main/java/server/haengdong/domain/MemberActionStatus.java +++ b/server/src/main/java/server/haengdong/domain/MemberActionStatus.java @@ -1,7 +1,16 @@ package server.haengdong.domain; +import java.util.Arrays; + public enum MemberActionStatus { IN, OUT, ; + + public static MemberActionStatus of(String status) { + return Arrays.stream(MemberActionStatus.values()) + .filter(s -> s.name().equals(status)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Invalid status: " + status)); + } } diff --git a/server/src/main/java/server/haengdong/domain/MemberGroupIdProvider.java b/server/src/main/java/server/haengdong/domain/MemberGroupIdProvider.java new file mode 100644 index 000000000..c4166e2be --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/MemberGroupIdProvider.java @@ -0,0 +1,11 @@ +package server.haengdong.domain; + +import org.springframework.stereotype.Component; + +@Component +public class MemberGroupIdProvider { + + public Long createGroupId() { + return System.currentTimeMillis(); + } +} diff --git a/server/src/main/java/server/haengdong/persistence/ActionRepository.java b/server/src/main/java/server/haengdong/persistence/ActionRepository.java index 72c573d91..7b7b838d2 100644 --- a/server/src/main/java/server/haengdong/persistence/ActionRepository.java +++ b/server/src/main/java/server/haengdong/persistence/ActionRepository.java @@ -3,6 +3,7 @@ import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import server.haengdong.domain.Action; import server.haengdong.domain.Event; @@ -17,5 +18,5 @@ public interface ActionRepository extends JpaRepository { ORDER BY a.sequence DESC LIMIT 1 """) - Optional findLastByEvent(Event event); + Optional findLastByEvent(@Param("event") Event event); } diff --git a/server/src/main/java/server/haengdong/persistence/EventRepository.java b/server/src/main/java/server/haengdong/persistence/EventRepository.java index 8a83d751f..5c08ca98c 100644 --- a/server/src/main/java/server/haengdong/persistence/EventRepository.java +++ b/server/src/main/java/server/haengdong/persistence/EventRepository.java @@ -7,6 +7,6 @@ @Repository public interface EventRepository extends JpaRepository { - + Optional findByToken(String token); } diff --git a/server/src/main/java/server/haengdong/persistence/MemberActionRepository.java b/server/src/main/java/server/haengdong/persistence/MemberActionRepository.java new file mode 100644 index 000000000..97d06618b --- /dev/null +++ b/server/src/main/java/server/haengdong/persistence/MemberActionRepository.java @@ -0,0 +1,16 @@ +package server.haengdong.persistence; + +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.Event; +import server.haengdong.domain.MemberAction; + +@Repository +public interface MemberActionRepository extends JpaRepository { + + @Query("select m from MemberAction m join fetch m.action where m.action.event = :event") + List findAllByEvent(@Param("event") Event event); +} diff --git a/server/src/main/java/server/haengdong/presentation/MemberActionController.java b/server/src/main/java/server/haengdong/presentation/MemberActionController.java new file mode 100644 index 000000000..e35bcfd7b --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/MemberActionController.java @@ -0,0 +1,27 @@ +package server.haengdong.presentation; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.MemberActionService; +import server.haengdong.presentation.request.MemberActionsSaveRequest; + +@RequiredArgsConstructor +@RestController +public class MemberActionController { + + private final MemberActionService memberActionService; + + @PostMapping("/api/events/{token}/actions/members") + public ResponseEntity saveMemberAction( + @PathVariable("token") String token, + @RequestBody MemberActionsSaveRequest request + ) { + memberActionService.saveMemberAction(token, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberActionSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberActionSaveRequest.java new file mode 100644 index 000000000..a69c51d41 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MemberActionSaveRequest.java @@ -0,0 +1,10 @@ +package server.haengdong.presentation.request; + +import server.haengdong.application.request.MemberActionSaveAppRequest; + +public record MemberActionSaveRequest(String name, String status) { + + public MemberActionSaveAppRequest toAppRequest() { + return new MemberActionSaveAppRequest(name, status); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java new file mode 100644 index 000000000..bfe80f0ee --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java @@ -0,0 +1,16 @@ +package server.haengdong.presentation.request; + +import java.util.List; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; + +public record MemberActionsSaveRequest(List actions) { + + public MemberActionsSaveAppRequest toAppRequest() { + List appRequests = actions.stream() + .map(MemberActionSaveRequest::toAppRequest) + .toList(); + + return new MemberActionsSaveAppRequest(appRequests); + } +} diff --git a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java new file mode 100644 index 000000000..a0ac9916f --- /dev/null +++ b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java @@ -0,0 +1,216 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; + +import java.util.List; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.domain.Action; +import server.haengdong.domain.Event; +import server.haengdong.domain.MemberAction; +import server.haengdong.domain.MemberActionStatus; +import server.haengdong.persistence.ActionRepository; +import server.haengdong.persistence.EventRepository; +import server.haengdong.persistence.MemberActionRepository; + +@SpringBootTest +class MemberActionFactoryTest { + + @Autowired + private MemberActionFactory memberActionFactory; + + @Autowired + private MemberActionRepository memberActionRepository; + + @Autowired + private ActionRepository actionRepository; + + @Autowired + private EventRepository eventRepository; + + @AfterEach + void tearDown() { + memberActionRepository.deleteAllInBatch(); + actionRepository.deleteAllInBatch(); + eventRepository.deleteAllInBatch(); + } + + @DisplayName("이전 멤버 액션이 시퀀스 기준으로 정렬되지 않은 상태에서 새로운 멤버 액션 요청을 검증한다.") + @Test + void createMemberActionsTest() { + Event event = eventRepository.save(new Event("우당탕탕 행동대장 백엔드 회식", "토다리_토큰")); + Action action1 = new Action(event, 1L); + Action action2 = new Action(event, 2L); + MemberAction memberAction1 = new MemberAction(action1, "토다리", MemberActionStatus.IN, 1L); + MemberAction memberAction2 = new MemberAction(action2, "토다리", MemberActionStatus.OUT, 2L); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); + List unorderedMemberActions = List.of(memberAction2, memberAction1); + Action startAction = new Action(event, 3L); + + assertThatThrownBy(() -> memberActionFactory.createMemberActions(request, unorderedMemberActions, startAction)) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("인원 변동 액션을 생성한다.") + @Test + void createMemberActionsTest1() { + Event event = eventRepository.save(new Event("우당탕탕 행동대장 백엔드 회식", "토다리_토큰")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest memberActionsSaveAppRequest = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); + Action startAction = new Action(event, 2L); + + List memberActions = memberActionFactory.createMemberActions(memberActionsSaveAppRequest, + List.of(memberAction), startAction); + + assertThat(memberActions).hasSize(1) + .extracting(MemberAction::getAction, MemberAction::getMemberName, MemberAction::getStatus) + .containsExactly( + tuple(startAction, "토다리", MemberActionStatus.OUT) + ); + } + + @DisplayName("현재 행사에 참여 중인 경우에 퇴장할 수 있다.") + @Test + void createMemberActionsTest2() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에서 퇴장한 경우에 입장할 수 있다.") + @Test + void createMemberActionsTest3() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action1 = new Action(event, 1L); + MemberAction memberAction1 = new MemberAction(action1, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction1); + Action action2 = new Action(event, 2L); + MemberAction memberAction2 = new MemberAction(action2, "토다리", MemberActionStatus.OUT, 2L); + memberActionRepository.save(memberAction2); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "IN"))); + Action startAction = new Action(event, 3L); + + assertThatCode( + () -> memberActionFactory.createMemberActions(request, List.of(memberAction1, memberAction2), + startAction)) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에 입장한 적 없는 경우에 입장할 수 있다.") + @Test + void createMemberActionsTest4() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다.") + @Test + void createMemberActionTest5() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "OUT"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(), startAction)) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("행사에 이미 참여 중인 경우 다시 입장할 수 없다.") + @Test + void createMemberActionTest6() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("한 명의 사용자는 동시에 여러 번 입장할 수 없다.") + @Test + void createMemberActionTest7() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "IN"), + new MemberActionSaveAppRequest("쿠키", "IN"))); + Action startAction = new Action(event, 1L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(), startAction)) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("한 명의 사용자는 동시에 여러 번 퇴장할 수 없다.") + @Test + void createMemberActionTest8() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "OUT"), + new MemberActionSaveAppRequest("쿠키", "OUT"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("한 명의 사용자는 입장과 퇴장을 동시에 할 수 없다.") + @Test + void createMemberActionTest9() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "IN"), + new MemberActionSaveAppRequest("쿠키", "OUT"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) + .isInstanceOf(IllegalArgumentException.class); + } +} diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java new file mode 100644 index 000000000..73a7c3d9d --- /dev/null +++ b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java @@ -0,0 +1,82 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThatCode; + +import java.util.List; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.domain.Action; +import server.haengdong.domain.Event; +import server.haengdong.domain.MemberAction; +import server.haengdong.domain.MemberActionStatus; +import server.haengdong.persistence.ActionRepository; +import server.haengdong.persistence.EventRepository; +import server.haengdong.persistence.MemberActionRepository; + +@SpringBootTest +class MemberActionServiceTest { + + @Autowired + private MemberActionService memberActionService; + + @Autowired + private MemberActionRepository memberActionRepository; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private ActionRepository actionRepository; + + @AfterEach + void tearDown() { + memberActionRepository.deleteAllInBatch(); + actionRepository.deleteAllInBatch(); + eventRepository.deleteAllInBatch(); + } + + @DisplayName("현재 행사에 참여하고 있는 경우에 나갈 수 있다") + @Test + void saveMemberActionTest() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "망쵸", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("망쵸", "OUT"))))) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에서 퇴장한 경우에 입장할 수 있다") + @Test + void saveMemberActionTest1() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action actionOne = new Action(event, 1L); + MemberAction memberActionOne = new MemberAction(actionOne, "망쵸", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberActionOne); + + Action actionTwo = new Action(event, 2L); + MemberAction memberActionTwo = new MemberAction(actionTwo, "망쵸", MemberActionStatus.OUT, 1L); + memberActionRepository.save(memberActionTwo); + + assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("망쵸", "IN"))))) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다") + @Test + void saveMemberActionTest2() { + MemberActionsSaveAppRequest appRequest = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("TOKEN", "OUT"))); + + assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", appRequest)) + .isInstanceOf(IllegalArgumentException.class); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java index bed814ae3..a1d67f0a1 100644 --- a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java @@ -32,10 +32,10 @@ class EventControllerTest { @MockBean private EventService eventService; - @DisplayName("이벤트를 생성한다") + @DisplayName("이벤트를 생성한다.") @Test void saveEvent() throws Exception { - EventSaveRequest eventSaveRequest = new EventSaveRequest("test"); + EventSaveRequest eventSaveRequest = new EventSaveRequest("토다리"); String requestBody = objectMapper.writeValueAsString(eventSaveRequest); String token = "TOKEN"; EventAppResponse eventAppResponse = new EventAppResponse(token); diff --git a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java new file mode 100644 index 000000000..8f9e71182 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java @@ -0,0 +1,49 @@ +package server.haengdong.presentation; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import server.haengdong.application.MemberActionService; +import server.haengdong.presentation.request.MemberActionSaveRequest; +import server.haengdong.presentation.request.MemberActionsSaveRequest; + +@WebMvcTest(MemberActionController.class) +class MemberActionControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private MemberActionService memberActionService; + + @DisplayName("참여자 행동을 추가한다.") + @Test + void saveMemberActionTest() throws Exception { + MemberActionsSaveRequest memberActionsSaveRequest = new MemberActionsSaveRequest(List.of( + new MemberActionSaveRequest("웨디", "IN"), + new MemberActionSaveRequest("소하", "IN"), + new MemberActionSaveRequest("토다리", "IN"), + new MemberActionSaveRequest("쿠키", "IN"))); + + String requestBody = objectMapper.writeValueAsString(memberActionsSaveRequest); + + mockMvc.perform(post("/api/events/TOKEN/actions/members") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()); + } +} From 22e4af89eba091145a12f3a892e2d81b2c84d475 Mon Sep 17 00:00:00 2001 From: Juhwan Kim <13selfesteem91@naver.com> Date: Mon, 22 Jul 2024 15:59:33 +0900 Subject: [PATCH 064/178] =?UTF-8?q?[BE]=20=ED=8C=A8=ED=82=A4=EC=A7=80=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD=20(#62)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: 패키지 구조 변경 * test: 패키지 구조 변경 --------- Co-authored-by: Arachneee --- .../haengdong/application/BillActionService.java | 12 ++++++------ .../server/haengdong/application/EventService.java | 6 +++--- .../haengdong/application/MemberActionFactory.java | 8 ++++---- .../haengdong/application/MemberActionService.java | 12 ++++++------ .../application/request/BillActionAppRequest.java | 4 ++-- .../application/request/EventAppRequest.java | 2 +- .../request/MemberActionSaveAppRequest.java | 6 +++--- .../application/response/EventAppResponse.java | 2 +- .../haengdong/domain/{ => action}/Action.java | 3 ++- .../action}/ActionRepository.java | 5 ++--- .../haengdong/domain/{ => action}/BillAction.java | 2 +- .../action}/BillActionRepository.java | 5 ++--- .../domain/{ => action}/MemberAction.java | 2 +- .../action}/MemberActionRepository.java | 5 ++--- .../domain/{ => action}/MemberActionStatus.java | 2 +- .../domain/{ => action}/MemberGroupIdProvider.java | 2 +- .../server/haengdong/domain/{ => event}/Event.java | 2 +- .../event}/EventRepository.java | 3 +-- .../haengdong/domain/{ => event}/EventStep.java | 2 +- .../domain/{ => event}/EventTokenProvider.java | 2 +- .../application/BillActionServiceTest.java | 8 ++++---- .../haengdong/application/EventServiceTest.java | 2 +- .../application/MemberActionFactoryTest.java | 14 +++++++------- .../application/MemberActionServiceTest.java | 14 +++++++------- .../haengdong/domain/{ => action}/ActionTest.java | 3 ++- .../domain/{ => action}/BillActionTest.java | 3 ++- 26 files changed, 65 insertions(+), 66 deletions(-) rename server/src/main/java/server/haengdong/domain/{ => action}/Action.java (91%) rename server/src/main/java/server/haengdong/{persistence => domain/action}/ActionRepository.java (83%) rename server/src/main/java/server/haengdong/domain/{ => action}/BillAction.java (97%) rename server/src/main/java/server/haengdong/{persistence => domain/action}/BillActionRepository.java (76%) rename server/src/main/java/server/haengdong/domain/{ => action}/MemberAction.java (97%) rename server/src/main/java/server/haengdong/{persistence => domain/action}/MemberActionRepository.java (80%) rename server/src/main/java/server/haengdong/domain/{ => action}/MemberActionStatus.java (90%) rename server/src/main/java/server/haengdong/domain/{ => action}/MemberGroupIdProvider.java (82%) rename server/src/main/java/server/haengdong/domain/{ => event}/Event.java (93%) rename server/src/main/java/server/haengdong/{persistence => domain/event}/EventRepository.java (78%) rename server/src/main/java/server/haengdong/domain/{ => event}/EventStep.java (94%) rename server/src/main/java/server/haengdong/domain/{ => event}/EventTokenProvider.java (84%) rename server/src/test/java/server/haengdong/domain/{ => action}/ActionTest.java (89%) rename server/src/test/java/server/haengdong/domain/{ => action}/BillActionTest.java (96%) diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java index 0c62c133f..272eee7e8 100644 --- a/server/src/main/java/server/haengdong/application/BillActionService.java +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -5,12 +5,12 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import server.haengdong.application.request.BillActionAppRequest; -import server.haengdong.domain.Action; -import server.haengdong.domain.BillAction; -import server.haengdong.domain.Event; -import server.haengdong.persistence.ActionRepository; -import server.haengdong.persistence.BillActionRepository; -import server.haengdong.persistence.EventRepository; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.action.ActionRepository; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.event.EventRepository; @RequiredArgsConstructor @Transactional(readOnly = true) diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java index 6a5304e32..5fc9cd01c 100644 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -4,9 +4,9 @@ import org.springframework.stereotype.Service; import server.haengdong.application.request.EventAppRequest; import server.haengdong.application.response.EventAppResponse; -import server.haengdong.domain.Event; -import server.haengdong.domain.EventTokenProvider; -import server.haengdong.persistence.EventRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventTokenProvider; +import server.haengdong.domain.event.EventRepository; @RequiredArgsConstructor @Service diff --git a/server/src/main/java/server/haengdong/application/MemberActionFactory.java b/server/src/main/java/server/haengdong/application/MemberActionFactory.java index d583967a0..46fd9ed1a 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionFactory.java +++ b/server/src/main/java/server/haengdong/application/MemberActionFactory.java @@ -7,10 +7,10 @@ import org.springframework.stereotype.Component; import server.haengdong.application.request.MemberActionSaveAppRequest; import server.haengdong.application.request.MemberActionsSaveAppRequest; -import server.haengdong.domain.Action; -import server.haengdong.domain.MemberAction; -import server.haengdong.domain.MemberActionStatus; -import server.haengdong.domain.MemberGroupIdProvider; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionStatus; +import server.haengdong.domain.action.MemberGroupIdProvider; @RequiredArgsConstructor @Component diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java index 491981b06..1acc88b03 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionService.java +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -5,12 +5,12 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import server.haengdong.application.request.MemberActionsSaveAppRequest; -import server.haengdong.domain.Action; -import server.haengdong.domain.Event; -import server.haengdong.domain.MemberAction; -import server.haengdong.persistence.ActionRepository; -import server.haengdong.persistence.EventRepository; -import server.haengdong.persistence.MemberActionRepository; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.ActionRepository; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.domain.action.MemberActionRepository; @RequiredArgsConstructor @Transactional(readOnly = true) diff --git a/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java index 33c335737..acd0149f9 100644 --- a/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java +++ b/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java @@ -1,7 +1,7 @@ package server.haengdong.application.request; -import server.haengdong.domain.Action; -import server.haengdong.domain.BillAction; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; public record BillActionAppRequest( String title, diff --git a/server/src/main/java/server/haengdong/application/request/EventAppRequest.java b/server/src/main/java/server/haengdong/application/request/EventAppRequest.java index 8db47eba9..1eea6adf4 100644 --- a/server/src/main/java/server/haengdong/application/request/EventAppRequest.java +++ b/server/src/main/java/server/haengdong/application/request/EventAppRequest.java @@ -1,6 +1,6 @@ package server.haengdong.application.request; -import server.haengdong.domain.Event; +import server.haengdong.domain.event.Event; public record EventAppRequest(String name) { diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java index a7c90efe4..f7f8d8fc2 100644 --- a/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java +++ b/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java @@ -1,8 +1,8 @@ package server.haengdong.application.request; -import server.haengdong.domain.Action; -import server.haengdong.domain.MemberAction; -import server.haengdong.domain.MemberActionStatus; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionStatus; public record MemberActionSaveAppRequest(String name, String status) { diff --git a/server/src/main/java/server/haengdong/application/response/EventAppResponse.java b/server/src/main/java/server/haengdong/application/response/EventAppResponse.java index 37b63dec2..f331d0011 100644 --- a/server/src/main/java/server/haengdong/application/response/EventAppResponse.java +++ b/server/src/main/java/server/haengdong/application/response/EventAppResponse.java @@ -1,6 +1,6 @@ package server.haengdong.application.response; -import server.haengdong.domain.Event; +import server.haengdong.domain.event.Event; public record EventAppResponse(String token) { diff --git a/server/src/main/java/server/haengdong/domain/Action.java b/server/src/main/java/server/haengdong/domain/action/Action.java similarity index 91% rename from server/src/main/java/server/haengdong/domain/Action.java rename to server/src/main/java/server/haengdong/domain/action/Action.java index be294dac3..11f91fc38 100644 --- a/server/src/main/java/server/haengdong/domain/Action.java +++ b/server/src/main/java/server/haengdong/domain/action/Action.java @@ -1,4 +1,4 @@ -package server.haengdong.domain; +package server.haengdong.domain.action; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; @@ -9,6 +9,7 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; +import server.haengdong.domain.event.Event; @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) diff --git a/server/src/main/java/server/haengdong/persistence/ActionRepository.java b/server/src/main/java/server/haengdong/domain/action/ActionRepository.java similarity index 83% rename from server/src/main/java/server/haengdong/persistence/ActionRepository.java rename to server/src/main/java/server/haengdong/domain/action/ActionRepository.java index 7b7b838d2..c2138e42f 100644 --- a/server/src/main/java/server/haengdong/persistence/ActionRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/ActionRepository.java @@ -1,12 +1,11 @@ -package server.haengdong.persistence; +package server.haengdong.domain.action; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import server.haengdong.domain.Action; -import server.haengdong.domain.Event; +import server.haengdong.domain.event.Event; @Repository public interface ActionRepository extends JpaRepository { diff --git a/server/src/main/java/server/haengdong/domain/BillAction.java b/server/src/main/java/server/haengdong/domain/action/BillAction.java similarity index 97% rename from server/src/main/java/server/haengdong/domain/BillAction.java rename to server/src/main/java/server/haengdong/domain/action/BillAction.java index 557715e4b..503715fa1 100644 --- a/server/src/main/java/server/haengdong/domain/BillAction.java +++ b/server/src/main/java/server/haengdong/domain/action/BillAction.java @@ -1,4 +1,4 @@ -package server.haengdong.domain; +package server.haengdong.domain.action; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; diff --git a/server/src/main/java/server/haengdong/persistence/BillActionRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java similarity index 76% rename from server/src/main/java/server/haengdong/persistence/BillActionRepository.java rename to server/src/main/java/server/haengdong/domain/action/BillActionRepository.java index 03db3056e..1ad7416aa 100644 --- a/server/src/main/java/server/haengdong/persistence/BillActionRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java @@ -1,11 +1,10 @@ -package server.haengdong.persistence; +package server.haengdong.domain.action; import java.util.List; import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import server.haengdong.domain.BillAction; -import server.haengdong.domain.Event; +import server.haengdong.domain.event.Event; @Repository public interface BillActionRepository extends JpaRepository { diff --git a/server/src/main/java/server/haengdong/domain/MemberAction.java b/server/src/main/java/server/haengdong/domain/action/MemberAction.java similarity index 97% rename from server/src/main/java/server/haengdong/domain/MemberAction.java rename to server/src/main/java/server/haengdong/domain/action/MemberAction.java index eb8d8fdec..6e5f0d805 100644 --- a/server/src/main/java/server/haengdong/domain/MemberAction.java +++ b/server/src/main/java/server/haengdong/domain/action/MemberAction.java @@ -1,4 +1,4 @@ -package server.haengdong.domain; +package server.haengdong.domain.action; import jakarta.persistence.CascadeType; import jakarta.persistence.Entity; diff --git a/server/src/main/java/server/haengdong/persistence/MemberActionRepository.java b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java similarity index 80% rename from server/src/main/java/server/haengdong/persistence/MemberActionRepository.java rename to server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java index 97d06618b..6c4769e61 100644 --- a/server/src/main/java/server/haengdong/persistence/MemberActionRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java @@ -1,12 +1,11 @@ -package server.haengdong.persistence; +package server.haengdong.domain.action; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import server.haengdong.domain.Event; -import server.haengdong.domain.MemberAction; +import server.haengdong.domain.event.Event; @Repository public interface MemberActionRepository extends JpaRepository { diff --git a/server/src/main/java/server/haengdong/domain/MemberActionStatus.java b/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java similarity index 90% rename from server/src/main/java/server/haengdong/domain/MemberActionStatus.java rename to server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java index 6172bdb4d..afcb31337 100644 --- a/server/src/main/java/server/haengdong/domain/MemberActionStatus.java +++ b/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java @@ -1,4 +1,4 @@ -package server.haengdong.domain; +package server.haengdong.domain.action; import java.util.Arrays; diff --git a/server/src/main/java/server/haengdong/domain/MemberGroupIdProvider.java b/server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java similarity index 82% rename from server/src/main/java/server/haengdong/domain/MemberGroupIdProvider.java rename to server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java index c4166e2be..9e32bd733 100644 --- a/server/src/main/java/server/haengdong/domain/MemberGroupIdProvider.java +++ b/server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java @@ -1,4 +1,4 @@ -package server.haengdong.domain; +package server.haengdong.domain.action; import org.springframework.stereotype.Component; diff --git a/server/src/main/java/server/haengdong/domain/Event.java b/server/src/main/java/server/haengdong/domain/event/Event.java similarity index 93% rename from server/src/main/java/server/haengdong/domain/Event.java rename to server/src/main/java/server/haengdong/domain/event/Event.java index 8c24edc4d..c6877e1a6 100644 --- a/server/src/main/java/server/haengdong/domain/Event.java +++ b/server/src/main/java/server/haengdong/domain/event/Event.java @@ -1,4 +1,4 @@ -package server.haengdong.domain; +package server.haengdong.domain.event; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; diff --git a/server/src/main/java/server/haengdong/persistence/EventRepository.java b/server/src/main/java/server/haengdong/domain/event/EventRepository.java similarity index 78% rename from server/src/main/java/server/haengdong/persistence/EventRepository.java rename to server/src/main/java/server/haengdong/domain/event/EventRepository.java index 5c08ca98c..6038c368b 100644 --- a/server/src/main/java/server/haengdong/persistence/EventRepository.java +++ b/server/src/main/java/server/haengdong/domain/event/EventRepository.java @@ -1,9 +1,8 @@ -package server.haengdong.persistence; +package server.haengdong.domain.event; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import server.haengdong.domain.Event; @Repository public interface EventRepository extends JpaRepository { diff --git a/server/src/main/java/server/haengdong/domain/EventStep.java b/server/src/main/java/server/haengdong/domain/event/EventStep.java similarity index 94% rename from server/src/main/java/server/haengdong/domain/EventStep.java rename to server/src/main/java/server/haengdong/domain/event/EventStep.java index b25035fa5..297abdb66 100644 --- a/server/src/main/java/server/haengdong/domain/EventStep.java +++ b/server/src/main/java/server/haengdong/domain/event/EventStep.java @@ -1,4 +1,4 @@ -package server.haengdong.domain; +package server.haengdong.domain.event; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; diff --git a/server/src/main/java/server/haengdong/domain/EventTokenProvider.java b/server/src/main/java/server/haengdong/domain/event/EventTokenProvider.java similarity index 84% rename from server/src/main/java/server/haengdong/domain/EventTokenProvider.java rename to server/src/main/java/server/haengdong/domain/event/EventTokenProvider.java index 54d455f35..6450f0dcf 100644 --- a/server/src/main/java/server/haengdong/domain/EventTokenProvider.java +++ b/server/src/main/java/server/haengdong/domain/event/EventTokenProvider.java @@ -1,4 +1,4 @@ -package server.haengdong.domain; +package server.haengdong.domain.event; import java.util.UUID; import org.springframework.stereotype.Component; diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java index df19b9e63..178e850e3 100644 --- a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java @@ -10,10 +10,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import server.haengdong.application.request.BillActionAppRequest; -import server.haengdong.domain.BillAction; -import server.haengdong.domain.Event; -import server.haengdong.persistence.BillActionRepository; -import server.haengdong.persistence.EventRepository; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.event.EventRepository; @SpringBootTest class BillActionServiceTest { diff --git a/server/src/test/java/server/haengdong/application/EventServiceTest.java b/server/src/test/java/server/haengdong/application/EventServiceTest.java index 5fef04b81..12a5a08a5 100644 --- a/server/src/test/java/server/haengdong/application/EventServiceTest.java +++ b/server/src/test/java/server/haengdong/application/EventServiceTest.java @@ -11,7 +11,7 @@ import org.springframework.boot.test.mock.mockito.MockBean; import server.haengdong.application.request.EventAppRequest; import server.haengdong.application.response.EventAppResponse; -import server.haengdong.domain.EventTokenProvider; +import server.haengdong.domain.event.EventTokenProvider; @SpringBootTest class EventServiceTest { diff --git a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java index a0ac9916f..b8251a307 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java @@ -13,13 +13,13 @@ import org.springframework.boot.test.context.SpringBootTest; import server.haengdong.application.request.MemberActionSaveAppRequest; import server.haengdong.application.request.MemberActionsSaveAppRequest; -import server.haengdong.domain.Action; -import server.haengdong.domain.Event; -import server.haengdong.domain.MemberAction; -import server.haengdong.domain.MemberActionStatus; -import server.haengdong.persistence.ActionRepository; -import server.haengdong.persistence.EventRepository; -import server.haengdong.persistence.MemberActionRepository; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionStatus; +import server.haengdong.domain.action.ActionRepository; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.domain.action.MemberActionRepository; @SpringBootTest class MemberActionFactoryTest { diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java index 73a7c3d9d..73a1f5376 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java @@ -10,13 +10,13 @@ import org.springframework.boot.test.context.SpringBootTest; import server.haengdong.application.request.MemberActionSaveAppRequest; import server.haengdong.application.request.MemberActionsSaveAppRequest; -import server.haengdong.domain.Action; -import server.haengdong.domain.Event; -import server.haengdong.domain.MemberAction; -import server.haengdong.domain.MemberActionStatus; -import server.haengdong.persistence.ActionRepository; -import server.haengdong.persistence.EventRepository; -import server.haengdong.persistence.MemberActionRepository; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionStatus; +import server.haengdong.domain.action.ActionRepository; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.domain.action.MemberActionRepository; @SpringBootTest class MemberActionServiceTest { diff --git a/server/src/test/java/server/haengdong/domain/ActionTest.java b/server/src/test/java/server/haengdong/domain/action/ActionTest.java similarity index 89% rename from server/src/test/java/server/haengdong/domain/ActionTest.java rename to server/src/test/java/server/haengdong/domain/action/ActionTest.java index a699fb04a..199a4f628 100644 --- a/server/src/test/java/server/haengdong/domain/ActionTest.java +++ b/server/src/test/java/server/haengdong/domain/action/ActionTest.java @@ -1,9 +1,10 @@ -package server.haengdong.domain; +package server.haengdong.domain.action; import static org.assertj.core.api.Assertions.assertThat; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import server.haengdong.domain.event.Event; class ActionTest { diff --git a/server/src/test/java/server/haengdong/domain/BillActionTest.java b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java similarity index 96% rename from server/src/test/java/server/haengdong/domain/BillActionTest.java rename to server/src/test/java/server/haengdong/domain/action/BillActionTest.java index 5789f8c94..d179ca6eb 100644 --- a/server/src/test/java/server/haengdong/domain/BillActionTest.java +++ b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java @@ -1,4 +1,4 @@ -package server.haengdong.domain; +package server.haengdong.domain.action; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -8,6 +8,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import server.haengdong.domain.event.Event; class BillActionTest { From e9ceb0f12bf34a5e8b9384a5d7fef70e3262df4b Mon Sep 17 00:00:00 2001 From: TaehunLee <85233397+Todari@users.noreply.github.com> Date: Mon, 22 Jul 2024 17:13:24 +0900 Subject: [PATCH 065/178] =?UTF-8?q?feat:=20api=20wrapping=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EC=83=9D=EC=84=B1=20(#68)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: JinHo Kim Co-authored-by: Pakxe Co-authored-by: Soyeon Choe --- client/src/apis/fetcher.ts | 126 +++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 client/src/apis/fetcher.ts diff --git a/client/src/apis/fetcher.ts b/client/src/apis/fetcher.ts new file mode 100644 index 000000000..55c28d708 --- /dev/null +++ b/client/src/apis/fetcher.ts @@ -0,0 +1,126 @@ +type Method = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE'; + +type Body = ReadableStream | XMLHttpRequestBodyInit; +type HeadersType = [string, string][] | Record | Headers; + +export type ObjectQueryParams = Record; + +type RequestProps = { + baseUrl: string; + endpoint: string; + headers?: HeadersType; + body?: Body | object | null; + queryParams?: ObjectQueryParams; + // errorMessage: string; +}; + +type FetcherProps = RequestProps & { + method: Method; +}; + +type Options = { + method: Method; + headers: HeadersType; + body?: Body | null; +}; + +const objectToQueryString = (params: ObjectQueryParams): string => { + return Object.entries(params) + .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`) + .join('&'); +}; + +export const requestGet = async ({headers = {}, ...args}: RequestProps): Promise => { + const response = await fetcher({ + ...args, + method: 'GET', + headers, + }); + + const data: T = await response.json(); + return data; +}; + +export const requestPatch = ({headers = {}, ...args}: RequestProps) => { + return fetcher({method: 'PATCH', headers, ...args}); +}; + +export const requestPut = ({headers = {}, ...args}: RequestProps) => { + return fetcher({method: 'PUT', headers, ...args}); +}; + +export const requestPost = ({headers = {}, ...args}: RequestProps) => { + return fetcher({method: 'POST', headers, ...args}); +}; + +export const requestDelete = ({headers = {}, ...args}: RequestProps) => { + return fetcher({method: 'DELETE', headers, ...args}); +}; + +const fetcher = ({method, baseUrl, endpoint, headers, body, queryParams}: FetcherProps) => { + // const token = generateBasicToken(USER_ID, USER_PASSWORD); + const options = { + method, + headers: { + 'Content-Type': 'application/json', + // Authorization: token, + ...headers, + }, + body: body ? JSON.stringify(body) : null, + }; + + let url = `${baseUrl}${endpoint}`; + + if (queryParams) url += `?${objectToQueryString(queryParams)}`; + + return errorHandler(url, options); +}; + +// class ErrorWithHeader extends Error { +// header: string; + +// constructor(header: string, message: string) { +// super(message); +// this.name = this.constructor.name; +// this.header = header; +// } +// } + +const errorHandler = async (url: string, options: Options) => { + try { + const response = await fetch(url, options); + if (!response.ok) { + const serverErrorMessage = await response.text(); + throw new Error(serverErrorMessage || ''); // 받은 에러 메세지가 없는 경우는 서버에게.. + } + return response; + } catch (error) { + console.error(error); + throw new Error('아 에러났다;; 인생이 행복해질거에요 에러덕분에요ㅎㅎ'); + // throw new ErrorWithHeader(errorMessageHeader, getErrorMessage(error)); + } +}; + +// export const ERROR_MESSAGE = { +// SYSTEM_FAULT: 'system error. 관리자에게 문의하십시오', +// OFFLINE: '네트워크 연결이 끊어졌습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.', +// UNKNOWN: '알 수 없는 에러입니다. 관리자에게 문의해주세요. (연락처...)', +// }; + +// const getErrorMessage = (error: unknown) => { +// return ERROR_MESSAGE.UNKNOWN; + +// if (error instanceof TypeError) return ERROR_MESSAGE.OFFLINE; + +// if (error instanceof Error) { +// const mappedErrorMessage = Object.entries(SERVER_ERROR_MESSAGE).find(([key]) => { +// const upperCaseErrorMessage = convertToUpperCase(error.message.split(SERVER_ERROR_MESSAGE_DIVIDER)[0]); + +// return upperCaseErrorMessage.includes(key); +// })?.[1]; + +// return mappedErrorMessage ?? ERROR_MESSAGE.UNKNOWN; +// } + +// return ERROR_MESSAGE.UNKNOWN; +// }; From 784745e092d84e02c24bba7b297ba20374319df2 Mon Sep 17 00:00:00 2001 From: Soyeon Choe <77609591+soi-ha@users.noreply.github.com> Date: Tue, 23 Jul 2024 10:33:50 +0900 Subject: [PATCH 066/178] =?UTF-8?q?[FE]=20@svgr/webpack=20=ED=94=8C?= =?UTF-8?q?=EB=9F=AC=EA=B7=B8=EC=9D=B8=20=EC=84=A4=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/package-lock.json | 2601 ++++++++++++++++++++++++++++++++++++-- client/package.json | 1 + client/webpack.config.js | 8 + 3 files changed, 2530 insertions(+), 80 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index 6542cbc8d..975d4461e 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -17,6 +17,7 @@ "devDependencies": { "@eslint/compat": "^1.1.0", "@eslint/js": "^9.6.0", + "@svgr/webpack": "^8.1.0", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "@typescript-eslint/eslint-plugin": "^7.16.0", @@ -47,6 +48,19 @@ "npm": ">=10.7.0" } }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", @@ -59,6 +73,95 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/compat-data": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.9.tgz", + "integrity": "sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz", + "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.9", + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-module-transforms": "^7.24.9", + "@babel/helpers": "^7.24.8", + "@babel/parser": "^7.24.8", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.9", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/@babel/core/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/core/node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/core/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/generator": { "version": "7.24.9", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.9.tgz", @@ -73,6 +176,162 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", + "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", + "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz", + "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.8.tgz", + "integrity": "sha512-4f6Oqnmyp2PP3olgUMmOwC3akxSm5aBYraQ6YDdKy7NcAMkDECHWG0DEnV6M2UAkERgIBhYt8S27rURPg7SxWA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.7.tgz", + "integrity": "sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", + "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "node_modules/@babel/helper-environment-visitor": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", @@ -107,6 +366,19 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", + "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-module-imports": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", @@ -119,10 +391,30 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-split-export-declaration": { + "node_modules/@babel/helper-module-transforms": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz", + "integrity": "sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", - "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", + "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", + "dev": true, "dependencies": { "@babel/types": "^7.24.7" }, @@ -130,103 +422,1602 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-string-parser": { + "node_modules/@babel/helper-plugin-utils": { "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", - "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "dev": true, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-validator-identifier": { + "node_modules/@babel/helper-remap-async-to-generator": { "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.7.tgz", + "integrity": "sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-wrap-function": "^7.24.7" + }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/highlight": { + "node_modules/@babel/helper-replace-supers": { "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz", + "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.7", + "@babel/helper-optimise-call-expression": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", + "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.7.tgz", + "integrity": "sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.24.7", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz", + "integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", + "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.7.tgz", + "integrity": "sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.7.tgz", + "integrity": "sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", + "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.7.tgz", + "integrity": "sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", + "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", + "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", + "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", + "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", + "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.7.tgz", + "integrity": "sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", + "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", + "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.7.tgz", + "integrity": "sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz", + "integrity": "sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", + "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.8.tgz", + "integrity": "sha512-VXy91c47uujj758ud9wx+OMgheXm4qJfyhj1P18YvlrQkNOSrwsteHk+EFS3OMGfhMhpZa0A+81eE7G4QC+3CA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-replace-supers": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", + "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/template": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", + "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", + "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", + "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", + "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", + "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", + "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", + "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.7.tgz", + "integrity": "sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", + "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.7.tgz", + "integrity": "sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", + "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", + "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", + "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", + "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-simple-access": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.7.tgz", + "integrity": "sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", + "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", + "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", + "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", + "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", + "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", + "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", + "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", + "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", + "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", + "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz", + "integrity": "sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", + "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", + "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-constant-elements": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.24.7.tgz", + "integrity": "sha512-7LidzZfUXyfZ8/buRW6qIIHBY8wAZ1OrY9c/wTr8YhZ6vMPo+Uc/CVFLYY1spZrEQlD4w5u8wjqk5NQ3OVqQKA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.7.tgz", + "integrity": "sha512-H/Snz9PFxKsS1JLI4dJLtnJgCJRoo0AUm3chP6NYr+9En1JMKloheEiLIhlp5MDVznWo+H3AAC1Mc8lmUEpsgg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.24.7.tgz", + "integrity": "sha512-+Dj06GDZEFRYvclU6k4bme55GKBEWUmByM/eoKuqg4zTNQHiApWRhQph5fxQB2wAEFvRzL1tOEj1RJ19wJrhoA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-jsx": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.24.7.tgz", + "integrity": "sha512-QG9EnzoGn+Qar7rxuW+ZOsbWOt56FvvI93xInqsZDC5fsekx1AlIO4KIJ5M+D0p0SqSH156EpmZyXq630B8OlQ==", + "dev": true, + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.7.tgz", + "integrity": "sha512-PLgBVk3fzbmEjBJ/u8kFzOqS9tUeDjiaWud/rRym/yjCo/M9cASPlnrd2ZmmZpQT40fOOrvR8jh+n8jikrOhNA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", + "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", + "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", + "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", + "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", + "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", + "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", + "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.8.tgz", + "integrity": "sha512-CgFgtN61BbdOGCP4fLaAMOPkzWUh6yQZNMr5YSt8uz2cZSSiQONCQFWqsE4NeVfOIhqDOlS9CR3WD91FzMeB2Q==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/plugin-syntax-typescript": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", + "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", + "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", + "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", + "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz", + "integrity": "sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==", + "dev": true, "dependencies": { - "color-convert": "^1.9.0" + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "node_modules/@babel/preset-env": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.8.tgz", + "integrity": "sha512-vObvMZB6hNWuDxhSaEPTKCwcqkAIuDtE+bQGn4XMXne1DSLzFVY8Vmj1bm+mUQXYNN8NmaQEO+r8MMbzPr1jBQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.24.8", + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.24.7", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.24.7", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoped-functions": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.24.7", + "@babel/plugin-transform-class-properties": "^7.24.7", + "@babel/plugin-transform-class-static-block": "^7.24.7", + "@babel/plugin-transform-classes": "^7.24.8", + "@babel/plugin-transform-computed-properties": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-dotall-regex": "^7.24.7", + "@babel/plugin-transform-duplicate-keys": "^7.24.7", + "@babel/plugin-transform-dynamic-import": "^7.24.7", + "@babel/plugin-transform-exponentiation-operator": "^7.24.7", + "@babel/plugin-transform-export-namespace-from": "^7.24.7", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.24.7", + "@babel/plugin-transform-json-strings": "^7.24.7", + "@babel/plugin-transform-literals": "^7.24.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-member-expression-literals": "^7.24.7", + "@babel/plugin-transform-modules-amd": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-modules-systemjs": "^7.24.7", + "@babel/plugin-transform-modules-umd": "^7.24.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-new-target": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-numeric-separator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-object-super": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-property-literals": "^7.24.7", + "@babel/plugin-transform-regenerator": "^7.24.7", + "@babel/plugin-transform-reserved-words": "^7.24.7", + "@babel/plugin-transform-shorthand-properties": "^7.24.7", + "@babel/plugin-transform-spread": "^7.24.7", + "@babel/plugin-transform-sticky-regex": "^7.24.7", + "@babel/plugin-transform-template-literals": "^7.24.7", + "@babel/plugin-transform-typeof-symbol": "^7.24.8", + "@babel/plugin-transform-unicode-escapes": "^7.24.7", + "@babel/plugin-transform-unicode-property-regex": "^7.24.7", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.24.7", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.4", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.37.1", + "semver": "^6.3.1" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/@babel/preset-react": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.24.7.tgz", + "integrity": "sha512-AAH4lEkpmzFWrGVlHaxJB7RLH21uPQ9+He+eFLWHmF9IuFQVugz8eAsamaW0DXRrTfco5zj1wWtpdcXJUOfsag==", + "dev": true, "dependencies": { - "has-flag": "^3.0.0" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "@babel/plugin-transform-react-display-name": "^7.24.7", + "@babel/plugin-transform-react-jsx": "^7.24.7", + "@babel/plugin-transform-react-jsx-development": "^7.24.7", + "@babel/plugin-transform-react-pure-annotations": "^7.24.7" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", - "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", - "bin": { - "parser": "bin/babel-parser.js" + "node_modules/@babel/preset-typescript": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.7.tgz", + "integrity": "sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "@babel/plugin-syntax-jsx": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.7", + "@babel/plugin-transform-typescript": "^7.24.7" }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true + }, "node_modules/@babel/runtime": { "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", @@ -845,41 +2636,319 @@ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@remix-run/router": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.17.1.tgz", + "integrity": "sha512-mCOMec4BKd6BRGBZeSnGiIgwsbLGp3yhVqAD8H+PxiRNEHgDpZb8J1TnrSDlg97t0ySKMQJTHCWBCmBpSmkF6Q==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", + "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", + "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", + "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", + "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", + "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", + "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", + "dev": true, + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", + "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", + "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", + "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", + "@svgr/babel-plugin-transform-svg-component": "8.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", + "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^8.1.3", + "snake-case": "^3.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", + "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.21.3", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", + "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "@svgr/hast-util-to-babel-ast": "8.0.0", + "svg-parser": "^2.0.4" }, "engines": { - "node": ">= 8" + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "node_modules/@svgr/plugin-svgo": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", + "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", "dev": true, - "optional": true, + "dependencies": { + "cosmiconfig": "^8.1.3", + "deepmerge": "^4.3.1", + "svgo": "^3.0.2" + }, "engines": { "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" } }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "node_modules/@svgr/webpack": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", + "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", "dev": true, + "dependencies": { + "@babel/core": "^7.21.3", + "@babel/plugin-transform-react-constant-elements": "^7.21.3", + "@babel/preset-env": "^7.20.2", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.21.0", + "@svgr/core": "8.1.0", + "@svgr/plugin-jsx": "8.1.0", + "@svgr/plugin-svgo": "8.1.0" + }, "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + "node": ">=14" }, "funding": { - "url": "https://opencollective.com/unts" + "type": "github", + "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@remix-run/router": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.17.1.tgz", - "integrity": "sha512-mCOMec4BKd6BRGBZeSnGiIgwsbLGp3yhVqAD8H+PxiRNEHgDpZb8J1TnrSDlg97t0ySKMQJTHCWBCmBpSmkF6Q==", + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "dev": true, "engines": { - "node": ">=14.0.0" + "node": ">=10.13.0" } }, "node_modules/@types/body-parser": { @@ -1995,6 +4064,54 @@ "node": ">=10" } }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", + "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.2", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz", + "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.1", + "core-js-compat": "^3.36.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", + "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -2197,6 +4314,18 @@ "tslib": "^2.0.3" } }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001642", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz", @@ -2426,6 +4555,19 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "dev": true }, + "node_modules/core-js-compat": { + "version": "3.37.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", + "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -2523,6 +4665,19 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, "node_modules/css-what": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", @@ -2547,6 +4702,39 @@ "node": ">=4" } }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "dev": true, + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "dev": true + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -4298,6 +6486,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/get-intrinsic": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", @@ -5723,6 +7920,12 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -5755,6 +7958,12 @@ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -6941,11 +9150,38 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, "node_modules/regexp.prototype.flags": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", @@ -6964,6 +9200,44 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dev": true, + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, "node_modules/relateurl": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", @@ -7464,6 +9738,16 @@ "node": ">=8" } }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -7861,6 +10145,117 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", + "dev": true + }, + "node_modules/svgo": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", + "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", + "dev": true, + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/svgo/node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/svgo/node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dev": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/svgo/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/synckit": { "version": "0.8.8", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", @@ -8246,6 +10641,46 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", @@ -8935,6 +11370,12 @@ } } }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, "node_modules/yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", diff --git a/client/package.json b/client/package.json index f94bea034..ba5abcff0 100644 --- a/client/package.json +++ b/client/package.json @@ -15,6 +15,7 @@ "devDependencies": { "@eslint/compat": "^1.1.0", "@eslint/js": "^9.6.0", + "@svgr/webpack": "^8.1.0", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "@typescript-eslint/eslint-plugin": "^7.16.0", diff --git a/client/webpack.config.js b/client/webpack.config.js index 10b9352b7..69df113fe 100644 --- a/client/webpack.config.js +++ b/client/webpack.config.js @@ -39,6 +39,14 @@ export default { test: /\.css$/i, use: ['style-loader', 'css-loader'], }, + { + test: /\.svg$/, + use: [ + { + loader: '@svgr/webpack', + }, + ], + }, ], }, plugins: [ From 880833a632a489cd5b503f4a85fbd3a09cdbfe14 Mon Sep 17 00:00:00 2001 From: Juhwan Kim <13selfesteem91@naver.com> Date: Tue, 23 Jul 2024 15:55:11 +0900 Subject: [PATCH 067/178] =?UTF-8?q?feat:=20=ED=96=89=EC=82=AC=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(#75)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: kunsanglee --- .../haengdong/application/EventService.java | 9 ++++++- .../response/EventDetailAppResponse.java | 10 ++++++++ .../presentation/EventController.java | 10 ++++++++ .../response/EventDetailResponse.java | 10 ++++++++ .../application/EventServiceTest.java | 24 +++++++++++++++++++ .../presentation/EventControllerTest.java | 16 +++++++++++++ 6 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java index 5fc9cd01c..ea4384148 100644 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -4,9 +4,10 @@ import org.springframework.stereotype.Service; import server.haengdong.application.request.EventAppRequest; import server.haengdong.application.response.EventAppResponse; +import server.haengdong.application.response.EventDetailAppResponse; import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventTokenProvider; import server.haengdong.domain.event.EventRepository; +import server.haengdong.domain.event.EventTokenProvider; @RequiredArgsConstructor @Service @@ -22,4 +23,10 @@ public EventAppResponse saveEvent(EventAppRequest request) { return EventAppResponse.of(event); } + + public EventDetailAppResponse findEvent(String token) { + Event event = eventRepository.findByToken(token).orElseThrow(() -> new IllegalArgumentException("")); + + return EventDetailAppResponse.of(event); + } } diff --git a/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java b/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java new file mode 100644 index 000000000..6e38826d4 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.event.Event; + +public record EventDetailAppResponse(String eventName) { + + public static EventDetailAppResponse of(Event event) { + return new EventDetailAppResponse(event.getName()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java index 5254a78ae..1cc7dc77a 100644 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -3,11 +3,14 @@ import java.net.URI; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import server.haengdong.application.EventService; import server.haengdong.application.response.EventAppResponse; import server.haengdong.presentation.request.EventSaveRequest; +import server.haengdong.presentation.response.EventDetailResponse; @RequiredArgsConstructor @RestController @@ -23,4 +26,11 @@ public ResponseEntity saveEvent(EventSaveRequest request) { .location(URI.create("events/" + eventAppResponse.token())) .build(); } + + @GetMapping("/api/events/{token}") + public ResponseEntity findEvent(@PathVariable("token") String token) { + EventDetailResponse eventDetailResponse = EventDetailResponse.of(eventService.findEvent(token)); + + return ResponseEntity.ok(eventDetailResponse); + } } diff --git a/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java b/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java new file mode 100644 index 000000000..c18694393 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.EventDetailAppResponse; + +public record EventDetailResponse(String eventName) { + + public static EventDetailResponse of(EventDetailAppResponse response) { + return new EventDetailResponse(response.eventName()); + } +} diff --git a/server/src/test/java/server/haengdong/application/EventServiceTest.java b/server/src/test/java/server/haengdong/application/EventServiceTest.java index 12a5a08a5..31b1c650e 100644 --- a/server/src/test/java/server/haengdong/application/EventServiceTest.java +++ b/server/src/test/java/server/haengdong/application/EventServiceTest.java @@ -4,6 +4,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -11,6 +12,9 @@ import org.springframework.boot.test.mock.mockito.MockBean; import server.haengdong.application.request.EventAppRequest; import server.haengdong.application.response.EventAppResponse; +import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; import server.haengdong.domain.event.EventTokenProvider; @SpringBootTest @@ -22,6 +26,14 @@ class EventServiceTest { @MockBean private EventTokenProvider eventTokenProvider; + @Autowired + private EventRepository eventRepository; + + @AfterEach + void tearDown() { + eventRepository.deleteAllInBatch(); + } + @DisplayName("행사를 생성한다") @Test void saveEventTest() { @@ -32,4 +44,16 @@ void saveEventTest() { assertThat(response.token()).isEqualTo("TOKEN"); } + + @DisplayName("토큰으로 행사를 조회한다.") + @Test + void findEventTest() { + String token = "TOKEN"; + Event event = new Event("행동대장 회식", token); + eventRepository.save(event); + + EventDetailAppResponse eventDetailAppResponse = eventService.findEvent(token); + + assertThat(eventDetailAppResponse.eventName()).isEqualTo("행동대장 회식"); + } } diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java index a1d67f0a1..c50431696 100644 --- a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java @@ -2,8 +2,10 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.databind.ObjectMapper; @@ -18,6 +20,7 @@ import server.haengdong.application.EventService; import server.haengdong.application.request.EventAppRequest; import server.haengdong.application.response.EventAppResponse; +import server.haengdong.application.response.EventDetailAppResponse; import server.haengdong.presentation.request.EventSaveRequest; @WebMvcTest(EventController.class) @@ -48,4 +51,17 @@ void saveEvent() throws Exception { .andExpect(status().isOk()) .andExpect(MockMvcResultMatchers.redirectedUrl("events/" + token)); } + + @DisplayName("토큰으로 행사를 조회한다.") + @Test + void findEventTest() throws Exception { + String token = "TOKEN"; + EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식"); + given(eventService.findEvent(token)).willReturn(eventDetailAppResponse); + + mockMvc.perform(get("/api/events/" + token)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.eventName").value("행동대장 회식")); + } } From ac916e8cb31426c1fa82c21de4518e457c552deb Mon Sep 17 00:00:00 2001 From: Juhwan Kim <13selfesteem91@naver.com> Date: Tue, 23 Jul 2024 16:30:48 +0900 Subject: [PATCH 068/178] =?UTF-8?q?[BE]=20=EC=84=A4=EC=A0=95=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=84=9C=EB=B8=8C=20=EB=AA=A8=EB=93=88=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20(#82)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 설정 파일을 서브모듈로 관리 Co-authored-by: kunsanglee Co-authored-by: Arachne Co-authored-by: khabh * feat: 테스트 설정 파일 추가 Co-authored-by: kunsanglee Co-authored-by: Arachne Co-authored-by: khabh * feat: 도커 파일 내 profile 설정 Co-authored-by: kunsanglee Co-authored-by: Arachne Co-authored-by: khabh * feat: gitflow에 서브 모듈 설정 Co-authored-by: kunsanglee Co-authored-by: Arachne Co-authored-by: khabh --------- Co-authored-by: kunsanglee Co-authored-by: Arachne Co-authored-by: khabh --- .github/workflows/backend-push.yml | 3 +++ .gitmodules | 3 +++ server/Dockerfile | 2 +- server/src/main/resources/application.yml | 28 +++++++++++++++-------- server/src/main/resources/config | 1 + server/src/test/resources/application.yml | 15 ++++++++++++ 6 files changed, 41 insertions(+), 11 deletions(-) create mode 100644 .gitmodules create mode 160000 server/src/main/resources/config create mode 100644 server/src/test/resources/application.yml diff --git a/.github/workflows/backend-push.yml b/.github/workflows/backend-push.yml index 5a8d5f4ef..a35eaea7b 100644 --- a/.github/workflows/backend-push.yml +++ b/.github/workflows/backend-push.yml @@ -21,6 +21,9 @@ jobs: steps: - name: CheckOut uses: actions/checkout@v4 + with: + token: ${{secrets.CONFIG_SUBMODULE_TOKEN}} + submodules: true - name: Set up JDK 17 uses: actions/setup-java@v4 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..a067fc391 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "server/src/main/resources/config"] + path = server/src/main/resources/config + url = https://github.com/woowacourse-teams/2024-haeng-dong-config.git diff --git a/server/Dockerfile b/server/Dockerfile index 38c565c85..66a2d0ab3 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -14,4 +14,4 @@ COPY --from=build /app/build/libs/*.jar /app/haengdong-0.0.1-SNAPSHOT.jar EXPOSE 8080 ENTRYPOINT ["java"] -CMD ["-jar", "haengdong-0.0.1-SNAPSHOT.jar"] +CMD ["-Dspring.profiles.active=dev", "-jar", "haengdong-0.0.1-SNAPSHOT.jar"] diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index 49c481eaa..aca841de8 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -1,15 +1,23 @@ spring: - h2: - console: - enabled: true - path: /h2-console datasource: - url: jdbc:h2:mem:database + url: jdbc:mysql://localhost:3306/haengdong + username: root + password: 1234 + driver-class-name: com.mysql.cj.jdbc.Driver + jpa: - defer-datasource-initialization: true - show-sql: true + hibernate: + ddl-auto: none properties: hibernate: - format_sql: true - hibernate: - ddl-auto: create-drop + dialect: org.hibernate.dialect.MySQL8Dialect + format_sql: true + show-sql: true + +--- + +spring: + config: + import: classpath:config/application-dev.yml + activate: + on-profile: dev diff --git a/server/src/main/resources/config b/server/src/main/resources/config new file mode 160000 index 000000000..c12697b65 --- /dev/null +++ b/server/src/main/resources/config @@ -0,0 +1 @@ +Subproject commit c12697b650b8a8adf27fd66377f6e62bb6b8a49d diff --git a/server/src/test/resources/application.yml b/server/src/test/resources/application.yml new file mode 100644 index 000000000..49c481eaa --- /dev/null +++ b/server/src/test/resources/application.yml @@ -0,0 +1,15 @@ +spring: + h2: + console: + enabled: true + path: /h2-console + datasource: + url: jdbc:h2:mem:database + jpa: + defer-datasource-initialization: true + show-sql: true + properties: + hibernate: + format_sql: true + hibernate: + ddl-auto: create-drop From 8665f7a7e1e9ea8a6869c00db3ab7dd1949d1e4b Mon Sep 17 00:00:00 2001 From: Juhwan Kim <13selfesteem91@naver.com> Date: Tue, 23 Jul 2024 17:27:29 +0900 Subject: [PATCH 069/178] =?UTF-8?q?[BE]=20=EC=9A=94=EC=B2=AD=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=EA=B0=80=20=EB=A7=B5=ED=95=91=EB=90=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0=20(#86)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: kunsanglee Co-authored-by: Arachneee Co-authored-by: khabh --- .../java/server/haengdong/presentation/EventController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java index 1cc7dc77a..538ca9c1e 100644 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -6,6 +6,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import server.haengdong.application.EventService; import server.haengdong.application.response.EventAppResponse; @@ -19,7 +20,7 @@ public class EventController { private final EventService eventService; @PostMapping("/api/events") - public ResponseEntity saveEvent(EventSaveRequest request) { + public ResponseEntity saveEvent(@RequestBody EventSaveRequest request) { EventAppResponse eventAppResponse = eventService.saveEvent(request.toAppRequest()); return ResponseEntity.ok() From 22c1ab79aeeadf8f6b99b3131e79b345de9e9cde Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Wed, 24 Jul 2024 10:56:45 +0900 Subject: [PATCH 070/178] =?UTF-8?q?feat:=20=ED=98=84=EC=9E=AC=20=EC=B0=B8?= =?UTF-8?q?=EC=97=AC=20=EC=9D=B8=EC=9B=90=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84=20(#70)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/MemberActionService.java | 27 +++++++++++--- .../response/CurrentMemberAppResponse.java | 10 +++++ .../domain/action/CurrentMembers.java | 37 +++++++++++++++++++ .../presentation/MemberActionController.java | 12 ++++++ .../response/CurrentMemberResponse.java | 10 +++++ .../response/CurrentMembersResponse.java | 15 ++++++++ .../application/MemberActionServiceTest.java | 29 ++++++++++----- .../domain/action/CurrentMembersTest.java | 30 +++++++++++++++ .../MemberActionControllerTest.java | 21 +++++++++++ 9 files changed, 176 insertions(+), 15 deletions(-) create mode 100644 server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java create mode 100644 server/src/main/java/server/haengdong/domain/action/CurrentMembers.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/CurrentMemberResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java create mode 100644 server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java index 1acc88b03..ba17b28c4 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionService.java +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -5,12 +5,14 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.application.response.CurrentMemberAppResponse; import server.haengdong.domain.action.Action; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.ActionRepository; -import server.haengdong.domain.event.EventRepository; +import server.haengdong.domain.action.CurrentMembers; +import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; @RequiredArgsConstructor @Transactional(readOnly = true) @@ -24,8 +26,7 @@ public class MemberActionService { @Transactional public void saveMemberAction(String token, MemberActionsSaveAppRequest request) { - Event event = eventRepository.findByToken(token) - .orElseThrow(() -> new IllegalArgumentException("event not found")); + Event event = findEvent(token); List findMemberActions = memberActionRepository.findAllByEvent(event); Action action = createStartAction(event); @@ -38,4 +39,20 @@ private Action createStartAction(Event event) { .map(Action::next) .orElse(Action.createFirst(event)); } + + public List getCurrentMembers(String token) { + Event event = findEvent(token); + List findMemberActions = memberActionRepository.findAllByEvent(event); + CurrentMembers currentMembers = CurrentMembers.of(findMemberActions); + + return currentMembers.getMembers() + .stream() + .map(CurrentMemberAppResponse::new) + .toList(); + } + + private Event findEvent(String token) { + return eventRepository.findByToken(token) + .orElseThrow(() -> new IllegalArgumentException("event not found")); + } } diff --git a/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java b/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java new file mode 100644 index 000000000..6c682d3e9 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.action.MemberAction; + +public record CurrentMemberAppResponse(String name) { + + public static CurrentMemberAppResponse of(MemberAction memberAction) { + return new CurrentMemberAppResponse(memberAction.getMemberName()); + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java b/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java new file mode 100644 index 000000000..e6843a404 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java @@ -0,0 +1,37 @@ +package server.haengdong.domain.action; + +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class CurrentMembers { + + private final Set members; + + public static CurrentMembers of(List memberActions) { + List sortedMemberActions = getSortedMemberActions(memberActions); + Set members = new HashSet<>(); + for (MemberAction memberAction : sortedMemberActions) { + String member = memberAction.getMemberName(); + if (memberAction.isSameStatus(MemberActionStatus.IN)) { + members.add(member); + continue; + } + members.remove(member); + } + + return new CurrentMembers(members); + } + + private static List getSortedMemberActions(List memberActions) { + return memberActions.stream() + .sorted(Comparator.comparing(MemberAction::getSequence)) + .toList(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/MemberActionController.java b/server/src/main/java/server/haengdong/presentation/MemberActionController.java index e35bcfd7b..cd45e3237 100644 --- a/server/src/main/java/server/haengdong/presentation/MemberActionController.java +++ b/server/src/main/java/server/haengdong/presentation/MemberActionController.java @@ -1,13 +1,17 @@ package server.haengdong.presentation; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import server.haengdong.application.MemberActionService; +import server.haengdong.application.response.CurrentMemberAppResponse; import server.haengdong.presentation.request.MemberActionsSaveRequest; +import server.haengdong.presentation.response.CurrentMembersResponse; @RequiredArgsConstructor @RestController @@ -24,4 +28,12 @@ public ResponseEntity saveMemberAction( return ResponseEntity.ok().build(); } + + @GetMapping("/api/events/{token}/members/current") + public ResponseEntity getCurrentMembers(@PathVariable("token") String token) { + List currentMembers = memberActionService.getCurrentMembers(token); + + return ResponseEntity.ok() + .body(CurrentMembersResponse.of(currentMembers)); + } } diff --git a/server/src/main/java/server/haengdong/presentation/response/CurrentMemberResponse.java b/server/src/main/java/server/haengdong/presentation/response/CurrentMemberResponse.java new file mode 100644 index 000000000..4308c7d17 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/CurrentMemberResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.CurrentMemberAppResponse; + +public record CurrentMemberResponse(String name) { + + public static CurrentMemberResponse of(CurrentMemberAppResponse response) { + return new CurrentMemberResponse(response.name()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java b/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java new file mode 100644 index 000000000..4eb915dd4 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java @@ -0,0 +1,15 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import server.haengdong.application.response.CurrentMemberAppResponse; + +public record CurrentMembersResponse(List members) { + + public static CurrentMembersResponse of(List currentMembers) { + List responses = currentMembers.stream() + .map(CurrentMemberResponse::of) + .toList(); + + return new CurrentMembersResponse(responses); + } +} diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java index 73a1f5376..378aa6006 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java @@ -1,6 +1,9 @@ package server.haengdong.application; import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; import java.util.List; import org.junit.jupiter.api.AfterEach; @@ -11,12 +14,11 @@ import server.haengdong.application.request.MemberActionSaveAppRequest; import server.haengdong.application.request.MemberActionsSaveAppRequest; import server.haengdong.domain.action.Action; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionStatus; import server.haengdong.domain.action.ActionRepository; -import server.haengdong.domain.event.EventRepository; +import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; @SpringBootTest class MemberActionServiceTest { @@ -40,12 +42,12 @@ void tearDown() { eventRepository.deleteAllInBatch(); } - @DisplayName("현재 행사에 참여하고 있는 경우에 나갈 수 있다") + @DisplayName("현재 행사에 참여하고 있는 경우에 나갈 수 있다.") @Test void saveMemberActionTest() { Event event = eventRepository.save(new Event("test", "TOKEN")); Action action = new Action(event, 1L); - MemberAction memberAction = new MemberAction(action, "망쵸", MemberActionStatus.IN, 1L); + MemberAction memberAction = new MemberAction(action, "망쵸", IN, 1L); memberActionRepository.save(memberAction); assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionsSaveAppRequest( @@ -53,16 +55,16 @@ void saveMemberActionTest() { .doesNotThrowAnyException(); } - @DisplayName("행사에서 퇴장한 경우에 입장할 수 있다") + @DisplayName("행사에서 퇴장한 경우에 입장할 수 있다.") @Test void saveMemberActionTest1() { Event event = eventRepository.save(new Event("test", "TOKEN")); Action actionOne = new Action(event, 1L); - MemberAction memberActionOne = new MemberAction(actionOne, "망쵸", MemberActionStatus.IN, 1L); + MemberAction memberActionOne = new MemberAction(actionOne, "망쵸", IN, 1L); memberActionRepository.save(memberActionOne); Action actionTwo = new Action(event, 2L); - MemberAction memberActionTwo = new MemberAction(actionTwo, "망쵸", MemberActionStatus.OUT, 1L); + MemberAction memberActionTwo = new MemberAction(actionTwo, "망쵸", OUT, 1L); memberActionRepository.save(memberActionTwo); assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionsSaveAppRequest( @@ -70,7 +72,7 @@ void saveMemberActionTest1() { .doesNotThrowAnyException(); } - @DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다") + @DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다.") @Test void saveMemberActionTest2() { MemberActionsSaveAppRequest appRequest = new MemberActionsSaveAppRequest( @@ -79,4 +81,11 @@ void saveMemberActionTest2() { assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", appRequest)) .isInstanceOf(IllegalArgumentException.class); } + + @DisplayName("이벤트가 없으면 현재 참여 인원을 조회할 수 없다.") + @Test + void getCurrentMembers() { + assertThatThrownBy(() -> memberActionService.getCurrentMembers("token")) + .isInstanceOf(IllegalArgumentException.class); + } } diff --git a/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java b/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java new file mode 100644 index 000000000..37ddca432 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java @@ -0,0 +1,30 @@ +package server.haengdong.domain.action; + +import static org.assertj.core.api.Assertions.assertThat; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.domain.event.Event; + +class CurrentMembersTest { + + @DisplayName("인원 변동 이력으로 현재 참여 인원을 계산한다.") + @Test + void of() { + Event event = new Event("test", "TOKEN"); + List memberActions = List.of( + new MemberAction(new Action(event, 1L), "망쵸", IN, 1L), + new MemberAction(new Action(event, 2L), "백호", IN, 1L), + new MemberAction(new Action(event, 3L), "백호", OUT, 1L), + new MemberAction(new Action(event, 4L), "웨디", IN, 1L) + ); + + CurrentMembers currentMembers = CurrentMembers.of(memberActions); + + assertThat(currentMembers.getMembers()) + .containsExactlyInAnyOrder("망쵸", "웨디"); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java index 8f9e71182..be8b89182 100644 --- a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java @@ -1,5 +1,9 @@ package server.haengdong.presentation; +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -13,7 +17,9 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import server.haengdong.application.MemberActionService; +import server.haengdong.application.response.CurrentMemberAppResponse; import server.haengdong.presentation.request.MemberActionSaveRequest; import server.haengdong.presentation.request.MemberActionsSaveRequest; @@ -46,4 +52,19 @@ void saveMemberActionTest() throws Exception { .andDo(print()) .andExpect(status().isOk()); } + + @DisplayName("현재 참여 인원을 조회합니다.") + @Test + void getCurrentMembers() throws Exception { + List currentMemberAppResponses = List.of(new CurrentMemberAppResponse("소하"), new CurrentMemberAppResponse("토다리")); + + given(memberActionService.getCurrentMembers(any())).willReturn(currentMemberAppResponses); + + mockMvc.perform(get("/api/events/{token}/members/current", "token") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.members[0].name").value(equalTo("소하"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.members[1].name").value(equalTo("토다리"))); + } } From 45861924b1fa71069cf619b9fb1ecf293889ef8b Mon Sep 17 00:00:00 2001 From: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> Date: Wed, 24 Jul 2024 11:41:04 +0900 Subject: [PATCH 071/178] =?UTF-8?q?design:=20=ED=83=AD=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20height=20=EC=86=8C=EC=88=98?= =?UTF-8?q?=EC=A0=90=20=EB=AC=B8=EC=A0=9C=20(#51)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * design: tab height 소수점 문제 해결 * fix: tab component after 가상태그를 활용해서 div 태그 제거 --- HDesign/src/components/Tab/Tab.style.ts | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/HDesign/src/components/Tab/Tab.style.ts b/HDesign/src/components/Tab/Tab.style.ts index 1e8054821..2242261b5 100644 --- a/HDesign/src/components/Tab/Tab.style.ts +++ b/HDesign/src/components/Tab/Tab.style.ts @@ -17,13 +17,23 @@ export const tabListStyle = (theme: Theme) => padding: '0.5rem', - borderBottomWidth: 1, - borderBottomStyle: 'solid', - borderBottomColor: theme.colors.gray, - backgroundColor: theme.colors.white, cursor: 'pointer', + + '&::after': { + position: 'absolute', + left: 0, + bottom: 0, + zIndex: 1, + + width: '100%', + height: '0.0625rem', + + backgroundColor: theme.colors.gray, + + content: '""', + }, }); export const tabItemStyle = css({ @@ -42,6 +52,7 @@ export const indicatorStyle = (theme: Theme, leftPosition: string, tabLength: nu position: 'absolute', left: leftPosition, bottom: 0, + zIndex: 2, width: `calc(100% / ${tabLength})`, height: '0.125rem', From 165618a4cf77022676dba4bf93a010a3770067e8 Mon Sep 17 00:00:00 2001 From: TaehunLee <85233397+Todari@users.noreply.github.com> Date: Wed, 24 Jul 2024 11:43:26 +0900 Subject: [PATCH 072/178] =?UTF-8?q?chore:=20=EB=B0=B0=ED=8F=AC,=20CI=20?= =?UTF-8?q?=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=A0=84=EB=9E=B5=20?= =?UTF-8?q?=EC=88=98=EB=A6=BD=20#32?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: frontend-push yaml 파일 추가 * chore: eslint-import-resolver-typescript 추가 * chore: eslint explicit-module-boundary-types 옵션 해제 * chore: noUnused tsconfig.json 설정 제거 * chore: eslint no-use-before-define 옵션 제거 * style: eslint 적용 * fix: workflow yml 파일 수정 --- .github/workflows/frontend-pll-request.yml | 34 +++++++++ client/eslint.config.mjs | 2 - client/package-lock.json | 70 +++++++++++++++++++ client/package.json | 1 + .../SetActionModalContent.tsx | 3 +- .../SetActionModalContent/SetPurchase.tsx | 1 + .../CompleteCreateEvent.tsx | 1 + client/src/pages/CreateEvent/CreateEvent.tsx | 1 + client/src/pages/Event/Event.tsx | 6 +- client/src/pages/Main/Main.tsx | 1 + client/src/router.tsx | 4 +- client/tsconfig.json | 4 +- 12 files changed, 120 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/frontend-pll-request.yml diff --git a/.github/workflows/frontend-pll-request.yml b/.github/workflows/frontend-pll-request.yml new file mode 100644 index 000000000..b94c4ceeb --- /dev/null +++ b/.github/workflows/frontend-pll-request.yml @@ -0,0 +1,34 @@ +name: frontend-pull-request + +on: + pull_request: + types: [opened, synchronize] + branches: [main, develop] + paths: + - 'client/**' + +jobs: + test: + runs-on: ubuntu-latest + + defaults: + run: + shell: bash + working-directory: ./client + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Node.js + uses: actions/setup-node@v2 + with: + node-version: '20.15.1' + + - name: Install dependencies + working-directory: ./client + run: npm install + + - name: Run lint + working-directory: ./client + run: npm run lint diff --git a/client/eslint.config.mjs b/client/eslint.config.mjs index 23794c081..46d23de19 100644 --- a/client/eslint.config.mjs +++ b/client/eslint.config.mjs @@ -32,8 +32,6 @@ export default [ 'react/react-in-jsx-scope': 'off', 'react/prop-types': 'off', 'react/jsx-uses-vars': 'error', - '@typescript-eslint/no-use-before-define': ['error'], - '@typescript-eslint/explicit-module-boundary-types': 'error', 'import/order': [ 'error', { diff --git a/client/package-lock.json b/client/package-lock.json index 975d4461e..781d96620 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -24,6 +24,7 @@ "@typescript-eslint/parser": "^7.16.0", "css-loader": "^7.1.2", "eslint": "^9.6.0", + "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.29.1", "eslint-plugin-jsx-a11y": "^6.9.0", "eslint-plugin-prettier": "^5.1.3", @@ -5454,6 +5455,54 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", + "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "enhanced-resolve": "^5.12.0", + "eslint-module-utils": "^2.7.4", + "fast-glob": "^3.3.1", + "get-tsconfig": "^4.5.0", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*" + } + }, + "node_modules/eslint-import-resolver-typescript/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint-import-resolver-typescript/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "node_modules/eslint-module-utils": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", @@ -6543,6 +6592,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-tsconfig": { + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.6.tgz", + "integrity": "sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", @@ -9312,6 +9373,15 @@ "node": ">=8" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/retry": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", diff --git a/client/package.json b/client/package.json index ba5abcff0..7b5875adc 100644 --- a/client/package.json +++ b/client/package.json @@ -22,6 +22,7 @@ "@typescript-eslint/parser": "^7.16.0", "css-loader": "^7.1.2", "eslint": "^9.6.0", + "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.29.1", "eslint-plugin-jsx-a11y": "^6.9.0", "eslint-plugin-prettier": "^5.1.3", diff --git a/client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx b/client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx index 5f052ce5c..2c293abc8 100644 --- a/client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx +++ b/client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx @@ -1,6 +1,7 @@ -import {Switch} from '@components/Switch'; import {useState} from 'react'; +import {Switch} from '@components/Switch'; + import SetPurchase from './SetPurchase'; import UpdateParticipants from './UpdateParticipants'; import {switchContainerStyle} from './SetActionModalContent.style'; diff --git a/client/src/components/Modal/SetActionModalContent/SetPurchase.tsx b/client/src/components/Modal/SetActionModalContent/SetPurchase.tsx index a71c5559b..3112f2d41 100644 --- a/client/src/components/Modal/SetActionModalContent/SetPurchase.tsx +++ b/client/src/components/Modal/SetActionModalContent/SetPurchase.tsx @@ -1,4 +1,5 @@ import {useState} from 'react'; + import {PurchaseInformation} from '@pages/Event/Event'; interface SetPurchaseProps { diff --git a/client/src/pages/CompleteCreateEvent/CompleteCreateEvent.tsx b/client/src/pages/CompleteCreateEvent/CompleteCreateEvent.tsx index 8c98d710e..083273c8a 100644 --- a/client/src/pages/CompleteCreateEvent/CompleteCreateEvent.tsx +++ b/client/src/pages/CompleteCreateEvent/CompleteCreateEvent.tsx @@ -1,5 +1,6 @@ import {useEffect, useState} from 'react'; import {useLocation, useNavigate} from 'react-router-dom'; + import {ROUTER_URLS} from '@constants/routerUrls'; const CompleteCreateEvent = () => { diff --git a/client/src/pages/CreateEvent/CreateEvent.tsx b/client/src/pages/CreateEvent/CreateEvent.tsx index d44cd5119..5ae0c8d5b 100644 --- a/client/src/pages/CreateEvent/CreateEvent.tsx +++ b/client/src/pages/CreateEvent/CreateEvent.tsx @@ -1,5 +1,6 @@ import {useState} from 'react'; import {useNavigate} from 'react-router-dom'; + import {ROUTER_URLS} from '@constants/routerUrls'; const CreateEvent = () => { diff --git a/client/src/pages/Event/Event.tsx b/client/src/pages/Event/Event.tsx index 20ae6b265..bded81860 100644 --- a/client/src/pages/Event/Event.tsx +++ b/client/src/pages/Event/Event.tsx @@ -1,9 +1,11 @@ -import {SetInitialParticipants} from '@components/Modal/SetInitialParticipants'; -import {Modal} from '@components/Modal'; import {useState} from 'react'; import {useParams} from 'react-router-dom'; + +import {SetInitialParticipants} from '@components/Modal/SetInitialParticipants'; import {SetActionModalContent} from '@components/Modal/SetActionModalContent'; +import {Modal} from '@components/Modal'; + import {orderHeaderStyle} from './Event.style'; export type PurchaseInformation = { diff --git a/client/src/pages/Main/Main.tsx b/client/src/pages/Main/Main.tsx index 13501b755..acaa4a167 100644 --- a/client/src/pages/Main/Main.tsx +++ b/client/src/pages/Main/Main.tsx @@ -1,4 +1,5 @@ import {useNavigate} from 'react-router-dom'; + import {ROUTER_URLS} from '@constants/routerUrls'; const Main = () => { diff --git a/client/src/router.tsx b/client/src/router.tsx index c9c1ea56f..04e1dfc5e 100644 --- a/client/src/router.tsx +++ b/client/src/router.tsx @@ -1,10 +1,12 @@ import {createBrowserRouter} from 'react-router-dom'; -import {ROUTER_URLS} from '@constants/routerUrls'; + import {MainPage} from '@pages/Main'; import {CreateEventPage} from '@pages/CreateEvent'; import {CompleteCreateEventPage} from '@pages/CompleteCreateEvent'; import {EventPage} from '@pages/Event'; +import {ROUTER_URLS} from '@constants/routerUrls'; + import App from './App'; const router = createBrowserRouter([ diff --git a/client/tsconfig.json b/client/tsconfig.json index 9f0da087d..f285f4d89 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -16,8 +16,8 @@ "jsx": "react-jsx", "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, + // "noUnusedLocals": true, + // "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, "types": ["jest"], From ce65a4c1d25d9c13da06d3491915f54f27878444 Mon Sep 17 00:00:00 2001 From: TaehunLee <85233397+Todari@users.noreply.github.com> Date: Wed, 24 Jul 2024 11:55:29 +0900 Subject: [PATCH 073/178] =?UTF-8?q?feat:=20=ED=96=89=EC=82=AC=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?(#87)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 행사 생성 페이지 디자인시스템 적용 * design : index.css 수정 * feat: 행사 생성 api 연결 * style: lint 적용 --- client/.prettierrc | 2 +- client/package-lock.json | 193 ++++++++---------- client/package.json | 3 + client/src/App.tsx | 7 +- client/src/apis/fetcher.ts | 6 +- client/src/apis/requestPostEvent.ts | 13 ++ client/src/constants/routerUrls.ts | 4 +- client/src/index.css | 6 +- client/src/pages/CompleteCreateEvent/index.ts | 1 - .../Complete.tsx} | 20 +- client/src/pages/Create/Name.tsx | 36 ++++ client/src/pages/Create/index.ts | 2 + client/src/pages/CreateEvent/CreateEvent.tsx | 27 --- client/src/pages/CreateEvent/index.ts | 1 - client/src/pages/Main/Main.tsx | 10 +- client/src/router.tsx | 11 +- client/tsconfig.json | 3 +- client/webpack.config.js | 2 + 18 files changed, 182 insertions(+), 165 deletions(-) create mode 100644 client/src/apis/requestPostEvent.ts delete mode 100644 client/src/pages/CompleteCreateEvent/index.ts rename client/src/pages/{CompleteCreateEvent/CompleteCreateEvent.tsx => Create/Complete.tsx} (50%) create mode 100644 client/src/pages/Create/Name.tsx create mode 100644 client/src/pages/Create/index.ts delete mode 100644 client/src/pages/CreateEvent/CreateEvent.tsx delete mode 100644 client/src/pages/CreateEvent/index.ts diff --git a/client/.prettierrc b/client/.prettierrc index a661f29c2..94ad823ef 100644 --- a/client/.prettierrc +++ b/client/.prettierrc @@ -9,4 +9,4 @@ "jsxSingleQuote": false, "bracketSpacing": false, "proseWrap": "preserve" -} +} \ No newline at end of file diff --git a/client/package-lock.json b/client/package-lock.json index 781d96620..2fda2f9e6 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -10,6 +10,9 @@ "license": "ISC", "dependencies": { "@emotion/react": "^11.11.4", + "@types/dotenv-webpack": "^7.0.7", + "dotenv-webpack": "^8.1.0", + "haengdong-design": "^0.1.3", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.24.1" @@ -2529,7 +2532,6 @@ "version": "0.3.6", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", - "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" @@ -2990,11 +2992,20 @@ "@types/node": "*" } }, + "node_modules/@types/dotenv-webpack": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/dotenv-webpack/-/dotenv-webpack-7.0.7.tgz", + "integrity": "sha512-tltVokFUeYuSjNmHc6N892Asu/JIQcnH2iUF5A29/VKqv9opq6KlrmnKd/Lt/bBikV/z0YN2K0kguTwWirYCMQ==", + "dependencies": { + "@types/node": "*", + "tapable": "^2.2.0", + "webpack": "^5" + } + }, "node_modules/@types/eslint": { "version": "8.56.10", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", - "dev": true, "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -3004,7 +3015,6 @@ "version": "3.7.7", "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dev": true, "dependencies": { "@types/eslint": "*", "@types/estree": "*" @@ -3013,8 +3023,7 @@ "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" }, "node_modules/@types/express": { "version": "4.17.21", @@ -3064,8 +3073,7 @@ "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" }, "node_modules/@types/json5": { "version": "0.0.29", @@ -3083,7 +3091,6 @@ "version": "20.14.10", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", - "dev": true, "dependencies": { "undici-types": "~5.26.4" } @@ -3451,7 +3458,6 @@ "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", - "dev": true, "dependencies": { "@webassemblyjs/helper-numbers": "1.11.6", "@webassemblyjs/helper-wasm-bytecode": "1.11.6" @@ -3460,26 +3466,22 @@ "node_modules/@webassemblyjs/floating-point-hex-parser": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", - "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", - "dev": true + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==" }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", - "dev": true, "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.11.6", "@webassemblyjs/helper-api-error": "1.11.6", @@ -3489,14 +3491,12 @@ "node_modules/@webassemblyjs/helper-wasm-bytecode": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", @@ -3508,7 +3508,6 @@ "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", - "dev": true, "dependencies": { "@xtuc/ieee754": "^1.2.0" } @@ -3517,7 +3516,6 @@ "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", - "dev": true, "dependencies": { "@xtuc/long": "4.2.2" } @@ -3525,14 +3523,12 @@ "node_modules/@webassemblyjs/utf8": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", @@ -3548,7 +3544,6 @@ "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", @@ -3561,7 +3556,6 @@ "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", @@ -3573,7 +3567,6 @@ "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-api-error": "1.11.6", @@ -3587,7 +3580,6 @@ "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.12.1", "@xtuc/long": "4.2.2" @@ -3640,14 +3632,12 @@ "node_modules/@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" }, "node_modules/@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, "node_modules/accepts": { "version": "1.3.8", @@ -3666,7 +3656,6 @@ "version": "8.12.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", - "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -3678,7 +3667,6 @@ "version": "1.9.5", "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", - "dev": true, "peerDependencies": { "acorn": "^8" } @@ -3696,7 +3684,6 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -3751,7 +3738,6 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, "peerDependencies": { "ajv": "^6.9.1" } @@ -3808,8 +3794,7 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/aria-query": { "version": "5.1.3", @@ -4192,8 +4177,7 @@ "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" }, "node_modules/brace-expansion": { "version": "2.0.1", @@ -4220,7 +4204,6 @@ "version": "4.23.2", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", - "dev": true, "funding": [ { "type": "opencollective", @@ -4251,8 +4234,7 @@ "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, "node_modules/bundle-name": { "version": "4.1.0", @@ -4331,7 +4313,6 @@ "version": "1.0.30001642", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz", "integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==", - "dev": true, "funding": [ { "type": "opencollective", @@ -4403,7 +4384,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", - "dev": true, "engines": { "node": ">=6.0" } @@ -4461,8 +4441,7 @@ "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, "node_modules/compressible": { "version": "2.0.18", @@ -4579,7 +4558,6 @@ "version": "8.3.6", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dev": true, "dependencies": { "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", @@ -4683,7 +4661,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "dev": true, "engines": { "node": ">= 6" }, @@ -4855,7 +4832,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -5034,7 +5010,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, "funding": [ { "type": "github", @@ -5075,12 +5050,41 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "dev": true, "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" } }, + "node_modules/dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "engines": { + "node": ">=10" + } + }, + "node_modules/dotenv-defaults": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dotenv-defaults/-/dotenv-defaults-2.0.2.tgz", + "integrity": "sha512-iOIzovWfsUHU91L5i8bJce3NYK5JXeAwH50Jh6+ARUdLiiGlYWfGw6UkzsYqaXZH/hjE/eCd/PlfM/qqyK0AMg==", + "dependencies": { + "dotenv": "^8.2.0" + } + }, + "node_modules/dotenv-webpack": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/dotenv-webpack/-/dotenv-webpack-8.1.0.tgz", + "integrity": "sha512-owK1JcsPkIobeqjVrk6h7jPED/W6ZpdFsMPR+5ursB7/SdgDyO+VzAU+szK8C8u3qUhtENyYnj8eyXMR5kkGag==", + "dependencies": { + "dotenv-defaults": "^2.0.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "webpack": "^4 || ^5" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -5096,8 +5100,7 @@ "node_modules/electron-to-chromium": { "version": "1.4.827", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.827.tgz", - "integrity": "sha512-VY+J0e4SFcNfQy19MEoMdaIcZLmDCprqvBtkii1WTCTQHpRvf5N8+3kTYCgL/PcntvwQvmMJWTuDPsq+IlhWKQ==", - "dev": true + "integrity": "sha512-VY+J0e4SFcNfQy19MEoMdaIcZLmDCprqvBtkii1WTCTQHpRvf5N8+3kTYCgL/PcntvwQvmMJWTuDPsq+IlhWKQ==" }, "node_modules/emoji-regex": { "version": "9.2.2", @@ -5127,7 +5130,6 @@ "version": "5.17.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", - "dev": true, "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -5300,8 +5302,7 @@ "node_modules/es-module-lexer": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", - "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", - "dev": true + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==" }, "node_modules/es-object-atoms": { "version": "1.0.0", @@ -5359,7 +5360,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "dev": true, "engines": { "node": ">=6" } @@ -5799,7 +5799,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -6041,7 +6040,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, "dependencies": { "estraverse": "^5.2.0" }, @@ -6053,7 +6051,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, "engines": { "node": ">=4.0" } @@ -6062,7 +6059,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, "engines": { "node": ">=4.0" } @@ -6071,7 +6067,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -6095,7 +6090,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, "engines": { "node": ">=0.8.x" } @@ -6168,8 +6162,7 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-diff": { "version": "1.3.0", @@ -6196,8 +6189,7 @@ "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "node_modules/fast-levenshtein": { "version": "2.0.6", @@ -6639,8 +6631,7 @@ "node_modules/glob-to-regexp": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" }, "node_modules/globals": { "version": "15.8.0", @@ -6705,8 +6696,7 @@ "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "node_modules/graphemer": { "version": "1.4.0", @@ -6714,6 +6704,22 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, + "node_modules/haengdong-design": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/haengdong-design/-/haengdong-design-0.1.3.tgz", + "integrity": "sha512-l/ED7kcE/LAZkuXxEFDU0j5k7Bac+t4dTJIxAAH8Ij9byaxdblzJF4DiRQ10AZ2RfuDzHYuI5MULq+18sU2cXA==", + "dependencies": { + "@emotion/react": "^11.11.4", + "@svgr/webpack": "^8.1.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.24.1" + }, + "engines": { + "node": ">=20.15.1", + "npm": ">=10.7.0" + } + }, "node_modules/handle-thing": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", @@ -6733,7 +6739,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -7763,7 +7768,6 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -7782,7 +7786,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -7815,8 +7818,7 @@ "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -7931,7 +7933,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "dev": true, "engines": { "node": ">=6.11.5" } @@ -8008,7 +8009,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dev": true, "dependencies": { "tslib": "^2.0.3" } @@ -8062,8 +8062,7 @@ "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" }, "node_modules/merge2": { "version": "1.4.1", @@ -8112,7 +8111,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -8121,7 +8119,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -8298,14 +8295,12 @@ "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dev": true, "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" @@ -8329,8 +8324,7 @@ "node_modules/node-releases": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -8357,7 +8351,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dev": true, "dependencies": { "boolbase": "^1.0.0" }, @@ -9012,7 +9005,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, "engines": { "node": ">=6" } @@ -9056,7 +9048,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, "dependencies": { "safe-buffer": "^5.1.0" } @@ -9482,7 +9473,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, "funding": [ { "type": "github", @@ -9533,7 +9523,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -9612,7 +9601,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, "dependencies": { "randombytes": "^2.1.0" } @@ -9833,7 +9821,6 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -9842,7 +9829,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -9851,7 +9837,6 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -10193,7 +10178,6 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -10346,7 +10330,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, "engines": { "node": ">=6" } @@ -10355,7 +10338,6 @@ "version": "5.31.2", "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.2.tgz", "integrity": "sha512-LGyRZVFm/QElZHy/CPr/O4eNZOZIzsrQ92y4v9UJe/pFJjypje2yI3C2FmPtvUEnhadlSbmG2nXtdcjHOjCfxw==", - "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -10373,7 +10355,6 @@ "version": "5.3.10", "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", - "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.20", "jest-worker": "^27.4.5", @@ -10528,8 +10509,7 @@ "node_modules/tslib": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/type-check": { "version": "0.4.0", @@ -10773,7 +10753,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -10803,7 +10782,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, "dependencies": { "punycode": "^2.1.0" } @@ -10851,7 +10829,6 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", - "dev": true, "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -10873,7 +10850,6 @@ "version": "5.93.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.93.0.tgz", "integrity": "sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA==", - "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.5", @@ -11182,7 +11158,6 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true, "engines": { "node": ">=10.13.0" } @@ -11467,4 +11442,4 @@ } } } -} +} \ No newline at end of file diff --git a/client/package.json b/client/package.json index 7b5875adc..f25247dc3 100644 --- a/client/package.json +++ b/client/package.json @@ -44,6 +44,9 @@ }, "dependencies": { "@emotion/react": "^11.11.4", + "@types/dotenv-webpack": "^7.0.7", + "dotenv-webpack": "^8.1.0", + "haengdong-design": "^0.1.3", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.24.1" diff --git a/client/src/App.tsx b/client/src/App.tsx index b6c73d8be..46618d881 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,7 +1,12 @@ +import {HDesignProvider} from 'haengdong-design'; import {Outlet} from 'react-router-dom'; const App: React.FC = () => { - return ; + return ( + + + + ); }; export default App; diff --git a/client/src/apis/fetcher.ts b/client/src/apis/fetcher.ts index 55c28d708..8df81a2c2 100644 --- a/client/src/apis/fetcher.ts +++ b/client/src/apis/fetcher.ts @@ -6,7 +6,7 @@ type HeadersType = [string, string][] | Record | Headers; export type ObjectQueryParams = Record; type RequestProps = { - baseUrl: string; + baseUrl?: string; endpoint: string; headers?: HeadersType; body?: Body | object | null; @@ -24,6 +24,8 @@ type Options = { body?: Body | null; }; +const API_BASE_URL = process.env.API_BASE_URL; + const objectToQueryString = (params: ObjectQueryParams): string => { return Object.entries(params) .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`) @@ -57,7 +59,7 @@ export const requestDelete = ({headers = {}, ...args}: RequestProps) => { return fetcher({method: 'DELETE', headers, ...args}); }; -const fetcher = ({method, baseUrl, endpoint, headers, body, queryParams}: FetcherProps) => { +const fetcher = ({baseUrl = API_BASE_URL, method, endpoint, headers, body, queryParams}: FetcherProps) => { // const token = generateBasicToken(USER_ID, USER_PASSWORD); const options = { method, diff --git a/client/src/apis/requestPostEvent.ts b/client/src/apis/requestPostEvent.ts new file mode 100644 index 000000000..cf6b4716e --- /dev/null +++ b/client/src/apis/requestPostEvent.ts @@ -0,0 +1,13 @@ +import {requestPost} from './fetcher'; + +interface RequestPostEventProps { + name: string; +} + +export const requestPostEvent = async ({name}: RequestPostEventProps) => { + requestPost({ + headers: {'Content-Type': 'application/json'}, + body: {name}, + endpoint: '/api/events', + }); +}; diff --git a/client/src/constants/routerUrls.ts b/client/src/constants/routerUrls.ts index c93f9fefe..eb4f6938b 100644 --- a/client/src/constants/routerUrls.ts +++ b/client/src/constants/routerUrls.ts @@ -1,7 +1,7 @@ export const ROUTER_URLS = { main: '', - createEvent: '/create-event', - completeCreateEvent: '/create-event/complete', + eventCreateName: '/event/create/name', + eventCreateComplete: '/event/create/complete', event: '/event', eventManage: '/event/:eventId', }; diff --git a/client/src/index.css b/client/src/index.css index c6eed01ac..936bdd319 100644 --- a/client/src/index.css +++ b/client/src/index.css @@ -1,5 +1,9 @@ body { max-width: 768px; + height: 100lvh; margin: 0 auto; - border: 1px solid gray; +} + +section { + width: 100%; } diff --git a/client/src/pages/CompleteCreateEvent/index.ts b/client/src/pages/CompleteCreateEvent/index.ts deleted file mode 100644 index a1e4fa117..000000000 --- a/client/src/pages/CompleteCreateEvent/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {default as CompleteCreateEventPage} from './CompleteCreateEvent'; diff --git a/client/src/pages/CompleteCreateEvent/CompleteCreateEvent.tsx b/client/src/pages/Create/Complete.tsx similarity index 50% rename from client/src/pages/CompleteCreateEvent/CompleteCreateEvent.tsx rename to client/src/pages/Create/Complete.tsx index 083273c8a..c2f499cb6 100644 --- a/client/src/pages/CompleteCreateEvent/CompleteCreateEvent.tsx +++ b/client/src/pages/Create/Complete.tsx @@ -1,5 +1,6 @@ import {useEffect, useState} from 'react'; import {useLocation, useNavigate} from 'react-router-dom'; +import {FixedButton, MainLayout, Title} from 'haengdong-design'; import {ROUTER_URLS} from '@constants/routerUrls'; @@ -11,7 +12,7 @@ const CompleteCreateEvent = () => { useEffect(() => { const getUrl = async () => { const eventTitle = location.search; - console.log(eventTitle); + // console.log(eventTitle); // const url = await fetch(); setUrl('hangsapage'); @@ -21,14 +22,15 @@ const CompleteCreateEvent = () => { }, []); return ( -

-

행사 개시

-

- 행사가 성공적으로 개시됐어요 :) 행사 링크를 통해서 참여자 관리가 가능해요. 관리를 위해서 행사 관리 링크를 보관해 - 주세요. -

- -
+ + {/* */} + + <FixedButton onClick={() => navigate(`${ROUTER_URLS.event}/${url}`)}>관리 페이지로 이동</FixedButton> + </MainLayout> ); }; diff --git a/client/src/pages/Create/Name.tsx b/client/src/pages/Create/Name.tsx new file mode 100644 index 000000000..ee847e258 --- /dev/null +++ b/client/src/pages/Create/Name.tsx @@ -0,0 +1,36 @@ +import {useState} from 'react'; +import {useNavigate} from 'react-router-dom'; +import {FixedButton, Input, MainLayout, TextButton, Title, TopNav} from 'haengdong-design'; + +import {requestPostEvent} from '@apis/requestPostEvent'; + +import {ROUTER_URLS} from '@constants/routerUrls'; + +const CreateEvent = () => { + const [eventTitle, setEventTitle] = useState(''); + const navigate = useNavigate(); + + const submitEventTitle = async (event: React.FormEvent<HTMLFormElement>) => { + event.preventDefault(); + const result = await requestPostEvent({name: eventTitle}); + + navigate(`${ROUTER_URLS.eventCreateComplete}?${new URLSearchParams({title: eventTitle})}`); + }; + + return ( + <MainLayout> + <TopNav navType="back" /> + <Title title="행사 이름 입력" description="시작할 행사 이름을 입력해 주세요." /> + <form onSubmit={submitEventTitle}> + <Input + value={eventTitle} + onChange={event => setEventTitle(event.target.value)} + placeholder="ex) 행동대장 야유회" + /> + <FixedButton>행동 개시!</FixedButton> + </form> + </MainLayout> + ); +}; + +export default CreateEvent; diff --git a/client/src/pages/Create/index.ts b/client/src/pages/Create/index.ts new file mode 100644 index 000000000..5ce37a93e --- /dev/null +++ b/client/src/pages/Create/index.ts @@ -0,0 +1,2 @@ +export {default as CreateNamePage} from './Name'; +export {default as CreateCompletePage} from './Complete'; diff --git a/client/src/pages/CreateEvent/CreateEvent.tsx b/client/src/pages/CreateEvent/CreateEvent.tsx deleted file mode 100644 index 5ae0c8d5b..000000000 --- a/client/src/pages/CreateEvent/CreateEvent.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import {useState} from 'react'; -import {useNavigate} from 'react-router-dom'; - -import {ROUTER_URLS} from '@constants/routerUrls'; - -const CreateEvent = () => { - const [eventTitle, setEventTitle] = useState(''); - const navigate = useNavigate(); - - const submitEventTitle = (event: React.FormEvent<HTMLFormElement>) => { - event.preventDefault(); - navigate(`${ROUTER_URLS.completeCreateEvent}?${new URLSearchParams({title: eventTitle})}`); - }; - - return ( - <section> - <h1>행사 생성하기</h1> - <h3>시작할 행사 이름을 입력해 주세요.</h3> - <form onSubmit={submitEventTitle}> - <input value={eventTitle} onChange={event => setEventTitle(event.target.value)} /> - <button>행동 개시!</button> - </form> - </section> - ); -}; - -export default CreateEvent; diff --git a/client/src/pages/CreateEvent/index.ts b/client/src/pages/CreateEvent/index.ts deleted file mode 100644 index ac2c26d0c..000000000 --- a/client/src/pages/CreateEvent/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {default as CreateEventPage} from './CreateEvent'; diff --git a/client/src/pages/Main/Main.tsx b/client/src/pages/Main/Main.tsx index acaa4a167..1cb9f6b26 100644 --- a/client/src/pages/Main/Main.tsx +++ b/client/src/pages/Main/Main.tsx @@ -1,4 +1,5 @@ import {useNavigate} from 'react-router-dom'; +import {FixedButton, MainLayout, Title} from 'haengdong-design'; import {ROUTER_URLS} from '@constants/routerUrls'; @@ -6,10 +7,11 @@ const Main = () => { const navigate = useNavigate(); return ( - <section> - <h1>행동대장</h1> - <button onClick={() => navigate(ROUTER_URLS.createEvent)}>행사 생성하기</button> - </section> + <MainLayout> + {/* <TopNav navType="back" /> */} + <Title title="행동대장" description="랜딩페이지입니다." /> + <FixedButton onClick={() => navigate(ROUTER_URLS.eventCreateName)}>행사 생성하기</FixedButton> + </MainLayout> ); }; diff --git a/client/src/router.tsx b/client/src/router.tsx index 04e1dfc5e..b6883623b 100644 --- a/client/src/router.tsx +++ b/client/src/router.tsx @@ -1,8 +1,7 @@ import {createBrowserRouter} from 'react-router-dom'; import {MainPage} from '@pages/Main'; -import {CreateEventPage} from '@pages/CreateEvent'; -import {CompleteCreateEventPage} from '@pages/CompleteCreateEvent'; +import {CreateNamePage, CreateCompletePage} from '@pages/Create'; import {EventPage} from '@pages/Event'; import {ROUTER_URLS} from '@constants/routerUrls'; @@ -20,12 +19,12 @@ const router = createBrowserRouter([ element: <MainPage />, }, { - path: ROUTER_URLS.createEvent, - element: <CreateEventPage />, + path: ROUTER_URLS.eventCreateName, + element: <CreateNamePage />, }, { - path: ROUTER_URLS.completeCreateEvent, - element: <CompleteCreateEventPage />, + path: ROUTER_URLS.eventCreateComplete, + element: <CreateCompletePage />, }, { path: ROUTER_URLS.eventManage, diff --git a/client/tsconfig.json b/client/tsconfig.json index f285f4d89..b049bf464 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -20,7 +20,7 @@ // "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, - "types": ["jest"], + "types": ["node", "jest"], "esModuleInterop": true, "strictNullChecks": true, "strictFunctionTypes": true, @@ -46,5 +46,6 @@ }, "outDir": "./dist" }, + "node": true, "include": ["src"] } diff --git a/client/webpack.config.js b/client/webpack.config.js index 69df113fe..b729f1020 100644 --- a/client/webpack.config.js +++ b/client/webpack.config.js @@ -3,6 +3,7 @@ import HtmlWebpackPlugin from 'html-webpack-plugin'; import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; import {ModifySourcePlugin, ConcatOperation} from 'modify-source-webpack-plugin'; import {fileURLToPath} from 'url'; +import Dotenv from 'dotenv-webpack'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -62,6 +63,7 @@ export default { }, ], }), + new Dotenv(), ], devServer: { port: 3000, From 1be9c4e9a92fe01d74bfd3397ebf01be91b51620 Mon Sep 17 00:00:00 2001 From: Pakxe <64801796+pakxe@users.noreply.github.com> Date: Wed, 24 Jul 2024 13:50:47 +0900 Subject: [PATCH 074/178] =?UTF-8?q?feat:=20=ED=96=89=EC=82=AC=20=ED=99=88?= =?UTF-8?q?=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B5=AC=ED=98=84=20(#88)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: env와 디자인 시스템 라이브러리 설치 * chore: 현재 불필요한 옵션 비활성화 * chore: env를 사용하기 위한 환경 세팅 * feat: 디자인 시스템 provider 사용 * design: index.css 정한대로 수정 * feat: apiBaseUrl 선언 * feat: router에 Home 페이지 연결 * feat: api호출 시 매번 들어가는 prefix 상수화 * feat: eventId를 타입에 포함시키기 위한 WithEventId 타입 선언 * feat: 지출 내역 추가 api 구현 * feat: 행사 생성 api 구현 * feat: 참여자 목록 갱신 api 구현 * feat: 정산 현황 요청 api 구현 * feat: 행사 이력 조회 api 구현 * feat: 참여자 별 정산 목록 컴포넌트 구현 * feat: 전체 지출 내역 컴포넌트 구현 * feat: router url 논의된 대로 선언 * feat: 정산 현황 검색을 위한 훅 구현 * feat: 스텝 목록을 관리하기 위한 훅 구현 * chore: 정산 현황 목 데이터 작성 * chore: 전체 지출 내역 목 데이터 작성 * feat: 홈 페이지 레이아웃 구현 * feat: 홈 페이지 안에 들어갈 컨텐츠 구현 * feat: Home -> HomePage로 import 할 수 있도록 export 작성 * feat: 스텝 목록에 필요한 타입 선언 * chore: url 경로 포멧 변경에 따른 수정 * chore: package-lock 업로드 * chore: import 개행 추가 * chore: 디자인 시스템 업데이트 * fix: inOutType 대문자로 넘기도록 수정 * feat: TopNav 추가 * chore: 사용하지 않는 util라이브러리 삭제 * chore: dotenv 세팅 수정 --- client/package-lock.json | 2300 +++++++---------- client/package.json | 3 +- client/src/apis/baseUrl.ts | 3 + client/src/apis/request/bill.ts | 19 + client/src/apis/request/event.ts | 17 + client/src/apis/request/member.ts | 19 + client/src/apis/request/report.ts | 18 + client/src/apis/request/stepList.ts | 14 + client/src/apis/tempPrefix.ts | 2 + client/src/apis/withEventId.type.ts | 3 + .../MemberReportList/MemberReportList.tsx | 21 + client/src/components/StepList/StepList.tsx | 24 + client/src/constants/routerUrls.ts | 1 + .../useSearchMemberReportList.tsx | 42 + client/src/hooks/useStepList/useStepList.tsx | 47 + client/src/mocks/memberReportSearchList.json | 10 + client/src/mocks/stepList.json | 86 + client/src/pages/CreateEvent/CreateEvent.tsx | 26 + client/src/pages/Home/HomeContent.tsx | 20 + client/src/pages/Home/HomeLayout.tsx | 19 + client/src/pages/Home/index.ts | 1 + client/src/router.tsx | 5 + client/src/types/stepList.ts | 52 + client/webpack.config.js | 2 + 24 files changed, 1448 insertions(+), 1306 deletions(-) create mode 100644 client/src/apis/baseUrl.ts create mode 100644 client/src/apis/request/bill.ts create mode 100644 client/src/apis/request/event.ts create mode 100644 client/src/apis/request/member.ts create mode 100644 client/src/apis/request/report.ts create mode 100644 client/src/apis/request/stepList.ts create mode 100644 client/src/apis/tempPrefix.ts create mode 100644 client/src/apis/withEventId.type.ts create mode 100644 client/src/components/MemberReportList/MemberReportList.tsx create mode 100644 client/src/components/StepList/StepList.tsx create mode 100644 client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.tsx create mode 100644 client/src/hooks/useStepList/useStepList.tsx create mode 100644 client/src/mocks/memberReportSearchList.json create mode 100644 client/src/mocks/stepList.json create mode 100644 client/src/pages/CreateEvent/CreateEvent.tsx create mode 100644 client/src/pages/Home/HomeContent.tsx create mode 100644 client/src/pages/Home/HomeLayout.tsx create mode 100644 client/src/pages/Home/index.ts create mode 100644 client/src/types/stepList.ts diff --git a/client/package-lock.json b/client/package-lock.json index 2fda2f9e6..d66f61a8b 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -12,7 +12,7 @@ "@emotion/react": "^11.11.4", "@types/dotenv-webpack": "^7.0.7", "dotenv-webpack": "^8.1.0", - "haengdong-design": "^0.1.3", + "haengdong-design": "^0.1.20", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.24.1" @@ -26,6 +26,7 @@ "@typescript-eslint/eslint-plugin": "^7.16.0", "@typescript-eslint/parser": "^7.16.0", "css-loader": "^7.1.2", + "dotenv": "^16.4.5", "eslint": "^9.6.0", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.29.1", @@ -56,7 +57,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -81,7 +81,6 @@ "version": "7.24.9", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.9.tgz", "integrity": "sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -90,7 +89,6 @@ "version": "7.24.9", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz", "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==", - "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.7", @@ -119,57 +117,12 @@ "node_modules/@babel/core/node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/@babel/core/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@babel/core/node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@babel/core/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, "node_modules/@babel/generator": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.9.tgz", - "integrity": "sha512-G8v3jRg+z8IwY1jHFxvCNhOPYPterE4XljNgdGTYfSTtzzwjIswIzIaSPSLs3R7yFuqnqNeay5rjICfqVr+/6A==", + "version": "7.24.10", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.10.tgz", + "integrity": "sha512-o9HBZL1G2129luEUlG1hB4N/nlYNWHnpwlND9eOMclRqqu1YDy2sSYVCFUZwl8I1Gxh+QSRrP2vD7EpUmFVXxg==", "dependencies": { "@babel/types": "^7.24.9", "@jridgewell/gen-mapping": "^0.3.5", @@ -184,7 +137,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", - "dev": true, "dependencies": { "@babel/types": "^7.24.7" }, @@ -196,7 +148,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", - "dev": true, "dependencies": { "@babel/traverse": "^7.24.7", "@babel/types": "^7.24.7" @@ -209,7 +160,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz", "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==", - "dev": true, "dependencies": { "@babel/compat-data": "^7.24.8", "@babel/helper-validator-option": "^7.24.8", @@ -221,29 +171,10 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/helper-create-class-features-plugin": { "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.8.tgz", "integrity": "sha512-4f6Oqnmyp2PP3olgUMmOwC3akxSm5aBYraQ6YDdKy7NcAMkDECHWG0DEnV6M2UAkERgIBhYt8S27rURPg7SxWA==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-environment-visitor": "^7.24.7", @@ -262,20 +193,10 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/helper-create-regexp-features-plugin": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.7.tgz", "integrity": "sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "regexpu-core": "^5.3.1", @@ -288,20 +209,10 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/helper-define-polyfill-provider": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", - "dev": true, "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", @@ -313,29 +224,6 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@babel/helper-environment-visitor": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", @@ -374,7 +262,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", - "dev": true, "dependencies": { "@babel/traverse": "^7.24.8", "@babel/types": "^7.24.8" @@ -399,7 +286,6 @@ "version": "7.24.9", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz", "integrity": "sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==", - "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.24.7", "@babel/helper-module-imports": "^7.24.7", @@ -418,7 +304,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", - "dev": true, "dependencies": { "@babel/types": "^7.24.7" }, @@ -430,7 +315,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -439,7 +323,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.7.tgz", "integrity": "sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-environment-visitor": "^7.24.7", @@ -456,7 +339,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz", "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==", - "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.24.7", "@babel/helper-member-expression-to-functions": "^7.24.7", @@ -473,7 +355,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", - "dev": true, "dependencies": { "@babel/traverse": "^7.24.7", "@babel/types": "^7.24.7" @@ -486,7 +367,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", - "dev": true, "dependencies": { "@babel/traverse": "^7.24.7", "@babel/types": "^7.24.7" @@ -526,7 +406,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -535,7 +414,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.7.tgz", "integrity": "sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==", - "dev": true, "dependencies": { "@babel/helper-function-name": "^7.24.7", "@babel/template": "^7.24.7", @@ -550,7 +428,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz", "integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==", - "dev": true, "dependencies": { "@babel/template": "^7.24.7", "@babel/types": "^7.24.8" @@ -573,62 +450,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/parser": { "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", @@ -644,7 +465,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.7.tgz", "integrity": "sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==", - "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -660,7 +480,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.7.tgz", "integrity": "sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -675,7 +494,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", @@ -692,7 +510,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.7.tgz", "integrity": "sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==", - "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -708,7 +525,6 @@ "version": "7.21.0-placeholder-for-preset-env.2", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "dev": true, "engines": { "node": ">=6.9.0" }, @@ -720,7 +536,6 @@ "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -732,7 +547,6 @@ "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" }, @@ -744,7 +558,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -759,7 +572,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -771,7 +583,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.3" }, @@ -783,7 +594,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -798,7 +608,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -813,7 +622,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -825,7 +633,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -837,7 +644,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -852,7 +658,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -864,7 +669,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -876,7 +680,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -888,7 +691,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -900,7 +702,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -912,7 +713,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -924,7 +724,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -939,7 +738,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -954,7 +752,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -969,7 +766,6 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", - "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -985,7 +781,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1000,7 +795,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.7.tgz", "integrity": "sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==", - "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7", @@ -1018,7 +812,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", - "dev": true, "dependencies": { "@babel/helper-module-imports": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7", @@ -1035,7 +828,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1050,7 +842,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.7.tgz", "integrity": "sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1065,7 +856,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz", "integrity": "sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==", - "dev": true, "dependencies": { "@babel/helper-create-class-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1081,7 +871,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", - "dev": true, "dependencies": { "@babel/helper-create-class-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7", @@ -1098,7 +887,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.8.tgz", "integrity": "sha512-VXy91c47uujj758ud9wx+OMgheXm4qJfyhj1P18YvlrQkNOSrwsteHk+EFS3OMGfhMhpZa0A+81eE7G4QC+3CA==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-compilation-targets": "^7.24.8", @@ -1120,7 +908,6 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, "engines": { "node": ">=4" } @@ -1129,7 +916,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/template": "^7.24.7" @@ -1145,7 +931,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.8" }, @@ -1160,7 +945,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", - "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1176,7 +960,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1191,7 +974,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3" @@ -1207,7 +989,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", - "dev": true, "dependencies": { "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1223,7 +1004,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" @@ -1239,7 +1019,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" @@ -1255,7 +1034,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.7.tgz", "integrity": "sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==", - "dev": true, "dependencies": { "@babel/helper-compilation-targets": "^7.24.7", "@babel/helper-function-name": "^7.24.7", @@ -1272,7 +1050,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-json-strings": "^7.8.3" @@ -1288,7 +1065,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.7.tgz", "integrity": "sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1303,7 +1079,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" @@ -1319,7 +1094,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1334,7 +1108,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", - "dev": true, "dependencies": { "@babel/helper-module-transforms": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1350,7 +1123,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", - "dev": true, "dependencies": { "@babel/helper-module-transforms": "^7.24.8", "@babel/helper-plugin-utils": "^7.24.8", @@ -1367,7 +1139,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.7.tgz", "integrity": "sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==", - "dev": true, "dependencies": { "@babel/helper-hoist-variables": "^7.24.7", "@babel/helper-module-transforms": "^7.24.7", @@ -1385,7 +1156,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", - "dev": true, "dependencies": { "@babel/helper-module-transforms": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1401,7 +1171,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", - "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1417,7 +1186,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1432,7 +1200,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" @@ -1448,7 +1215,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-numeric-separator": "^7.10.4" @@ -1464,7 +1230,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", - "dev": true, "dependencies": { "@babel/helper-compilation-targets": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7", @@ -1482,7 +1247,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-replace-supers": "^7.24.7" @@ -1498,7 +1262,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" @@ -1514,7 +1277,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.8", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", @@ -1531,7 +1293,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1546,7 +1307,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz", "integrity": "sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==", - "dev": true, "dependencies": { "@babel/helper-create-class-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1562,7 +1322,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-create-class-features-plugin": "^7.24.7", @@ -1580,7 +1339,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1595,7 +1353,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.24.7.tgz", "integrity": "sha512-7LidzZfUXyfZ8/buRW6qIIHBY8wAZ1OrY9c/wTr8YhZ6vMPo+Uc/CVFLYY1spZrEQlD4w5u8wjqk5NQ3OVqQKA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1610,7 +1367,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.7.tgz", "integrity": "sha512-H/Snz9PFxKsS1JLI4dJLtnJgCJRoo0AUm3chP6NYr+9En1JMKloheEiLIhlp5MDVznWo+H3AAC1Mc8lmUEpsgg==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1625,7 +1381,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.24.7.tgz", "integrity": "sha512-+Dj06GDZEFRYvclU6k4bme55GKBEWUmByM/eoKuqg4zTNQHiApWRhQph5fxQB2wAEFvRzL1tOEj1RJ19wJrhoA==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-module-imports": "^7.24.7", @@ -1644,7 +1399,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.24.7.tgz", "integrity": "sha512-QG9EnzoGn+Qar7rxuW+ZOsbWOt56FvvI93xInqsZDC5fsekx1AlIO4KIJ5M+D0p0SqSH156EpmZyXq630B8OlQ==", - "dev": true, "dependencies": { "@babel/plugin-transform-react-jsx": "^7.24.7" }, @@ -1659,7 +1413,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.7.tgz", "integrity": "sha512-PLgBVk3fzbmEjBJ/u8kFzOqS9tUeDjiaWud/rRym/yjCo/M9cASPlnrd2ZmmZpQT40fOOrvR8jh+n8jikrOhNA==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1675,7 +1428,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "regenerator-transform": "^0.15.2" @@ -1691,7 +1443,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1706,7 +1457,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1721,7 +1471,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" @@ -1737,7 +1486,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1752,7 +1500,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1767,7 +1514,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.8" }, @@ -1782,7 +1528,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.8.tgz", "integrity": "sha512-CgFgtN61BbdOGCP4fLaAMOPkzWUh6yQZNMr5YSt8uz2cZSSiQONCQFWqsE4NeVfOIhqDOlS9CR3WD91FzMeB2Q==", - "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-create-class-features-plugin": "^7.24.8", @@ -1800,7 +1545,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1815,7 +1559,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", - "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1831,7 +1574,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", - "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1847,7 +1589,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz", "integrity": "sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==", - "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1863,7 +1604,6 @@ "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.8.tgz", "integrity": "sha512-vObvMZB6hNWuDxhSaEPTKCwcqkAIuDtE+bQGn4XMXne1DSLzFVY8Vmj1bm+mUQXYNN8NmaQEO+r8MMbzPr1jBQ==", - "dev": true, "dependencies": { "@babel/compat-data": "^7.24.8", "@babel/helper-compilation-targets": "^7.24.8", @@ -1954,20 +1694,10 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/preset-modules": { "version": "0.1.6-no-external-plugins", "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/types": "^7.4.4", @@ -1981,7 +1711,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.24.7.tgz", "integrity": "sha512-AAH4lEkpmzFWrGVlHaxJB7RLH21uPQ9+He+eFLWHmF9IuFQVugz8eAsamaW0DXRrTfco5zj1wWtpdcXJUOfsag==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-validator-option": "^7.24.7", @@ -2001,7 +1730,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.7.tgz", "integrity": "sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-validator-option": "^7.24.7", @@ -2019,8 +1747,7 @@ "node_modules/@babel/regjsgen": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", - "dev": true + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "node_modules/@babel/runtime": { "version": "7.24.8", @@ -2066,22 +1793,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/@babel/traverse/node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -2090,11 +1801,6 @@ "node": ">=4" } }, - "node_modules/@babel/traverse/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/@babel/types": { "version": "7.24.9", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.9.tgz", @@ -2118,15 +1824,15 @@ } }, "node_modules/@emotion/babel-plugin": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", - "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz", + "integrity": "sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==", "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", - "@emotion/hash": "^0.9.1", - "@emotion/memoize": "^0.8.1", - "@emotion/serialize": "^1.1.2", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.2.0", "babel-plugin-macros": "^3.1.0", "convert-source-map": "^1.5.0", "escape-string-regexp": "^4.0.0", @@ -2135,59 +1841,40 @@ "stylis": "4.2.0" } }, - "node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@emotion/babel-plugin/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@emotion/cache": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", - "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", - "dependencies": { - "@emotion/memoize": "^0.8.1", - "@emotion/sheet": "^1.2.2", - "@emotion/utils": "^1.2.1", - "@emotion/weak-memoize": "^0.3.1", + "version": "11.13.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.0.tgz", + "integrity": "sha512-hPV345J/tH0Cwk2wnU/3PBzORQ9HeX+kQSbwI+jslzpRCHE6fSGTohswksA/Ensr8znPzwfzKZCmAM9Lmlhp7g==", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", "stylis": "4.2.0" } }, "node_modules/@emotion/hash": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", - "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==" }, "node_modules/@emotion/memoize": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", - "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" }, "node_modules/@emotion/react": { - "version": "11.11.4", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.4.tgz", - "integrity": "sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==", + "version": "11.13.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.0.tgz", + "integrity": "sha512-WkL+bw1REC2VNV1goQyfxjx1GYJkcc23CRQkXX+vZNLINyfI7o+uUn/rTGPt/xJ3bJHd5GcljgnxHf4wRw5VWQ==", "dependencies": { "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.11.0", - "@emotion/cache": "^11.11.0", - "@emotion/serialize": "^1.1.3", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", - "@emotion/utils": "^1.2.1", - "@emotion/weak-memoize": "^0.3.1", + "@emotion/babel-plugin": "^11.12.0", + "@emotion/cache": "^11.13.0", + "@emotion/serialize": "^1.3.0", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", "hoist-non-react-statics": "^3.3.1" }, "peerDependencies": { @@ -2200,44 +1887,44 @@ } }, "node_modules/@emotion/serialize": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.4.tgz", - "integrity": "sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.0.tgz", + "integrity": "sha512-jACuBa9SlYajnpIVXB+XOXnfJHyckDfe6fOpORIM6yhBDlqGuExvDdZYHDQGoDf3bZXGv7tNr+LpLjJqiEQ6EA==", "dependencies": { - "@emotion/hash": "^0.9.1", - "@emotion/memoize": "^0.8.1", - "@emotion/unitless": "^0.8.1", - "@emotion/utils": "^1.2.1", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.9.0", + "@emotion/utils": "^1.4.0", "csstype": "^3.0.2" } }, "node_modules/@emotion/sheet": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", - "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==" }, "node_modules/@emotion/unitless": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", - "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.9.0.tgz", + "integrity": "sha512-TP6GgNZtmtFaFcsOgExdnfxLLpRDla4Q66tnenA9CktvVSdNKDvMVuUah4QvWPIpNjrWsGg3qeGo9a43QooGZQ==" }, "node_modules/@emotion/use-insertion-effect-with-fallbacks": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", - "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz", + "integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==", "peerDependencies": { "react": ">=16.8.0" } }, "node_modules/@emotion/utils": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", - "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.0.tgz", + "integrity": "sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ==" }, "node_modules/@emotion/weak-memoize": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", - "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", @@ -2264,18 +1951,18 @@ } }, "node_modules/@eslint/compat": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.1.0.tgz", - "integrity": "sha512-s9Wi/p25+KbzxKlDm3VshQdImhWk+cbdblhwGNnyCU5lpSwtWa4v7VQCxSki0FAUrGA3s8nCWgYzAH41mwQVKQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.1.1.tgz", + "integrity": "sha512-lpHyRyplhGPL5mGEh6M9O5nnKk0Gz4bFI+Zu6tKlPpDUN7XshWvH9C/px4UVm87IAANE0W81CEsNGbS1KlzXpA==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/config-array": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.0.tgz", - "integrity": "sha512-A68TBu6/1mHHuc5YJL0U0VVeGNiklLAL6rRmhTCP2B5XjWLMnrX+HkO+IAXyHvks5cyyY1jjK5ITPQ1HGS2EVA==", + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", + "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", "dev": true, "dependencies": { "@eslint/object-schema": "^2.1.4", @@ -2296,23 +1983,6 @@ "concat-map": "0.0.1" } }, - "node_modules/@eslint/config-array/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/@eslint/config-array/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -2325,12 +1995,6 @@ "node": "*" } }, - "node_modules/@eslint/config-array/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@eslint/eslintrc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", @@ -2364,23 +2028,6 @@ "concat-map": "0.0.1" } }, - "node_modules/@eslint/eslintrc/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/@eslint/eslintrc/node_modules/globals": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", @@ -2405,16 +2052,10 @@ "node": "*" } }, - "node_modules/@eslint/eslintrc/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@eslint/js": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.6.0.tgz", - "integrity": "sha512-D9B0/3vNg44ZeWbYMpBoXqNP4j6eQD5vNwIlGAuFRRzK/WtT/jvDQW3Bi9kkf3PMDMlM7Yi+73VLUsn5bJcl8A==", + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.7.0.tgz", + "integrity": "sha512-ChuWDQenef8OSFnvuxv0TCVxEwmu3+hPNKvM9B34qpM0rDRbjL8t5QkQeHHeAfsKQjuH9wS82WeCi1J/owatng==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2669,9 +2310,9 @@ } }, "node_modules/@remix-run/router": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.17.1.tgz", - "integrity": "sha512-mCOMec4BKd6BRGBZeSnGiIgwsbLGp3yhVqAD8H+PxiRNEHgDpZb8J1TnrSDlg97t0ySKMQJTHCWBCmBpSmkF6Q==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.18.0.tgz", + "integrity": "sha512-L3jkqmqoSVBVKHfpGZmLrex0lxR5SucGA0sUfFzGctehw+S/ggL9L/0NnC5mw6P8HUWpFZ3nQw3cRApjjWx9Sw==", "engines": { "node": ">=14.0.0" } @@ -2680,7 +2321,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", - "dev": true, "engines": { "node": ">=14" }, @@ -2696,7 +2336,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", - "dev": true, "engines": { "node": ">=14" }, @@ -2712,7 +2351,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", - "dev": true, "engines": { "node": ">=14" }, @@ -2728,7 +2366,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", - "dev": true, "engines": { "node": ">=14" }, @@ -2744,7 +2381,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", - "dev": true, "engines": { "node": ">=14" }, @@ -2760,7 +2396,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", - "dev": true, "engines": { "node": ">=14" }, @@ -2776,7 +2411,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", - "dev": true, "engines": { "node": ">=14" }, @@ -2792,7 +2426,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", - "dev": true, "engines": { "node": ">=12" }, @@ -2808,7 +2441,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", - "dev": true, "dependencies": { "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", @@ -2834,7 +2466,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", - "dev": true, "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", @@ -2854,7 +2485,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", - "dev": true, "dependencies": { "@babel/types": "^7.21.3", "entities": "^4.4.0" @@ -2867,23 +2497,10 @@ "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@svgr/hast-util-to-babel-ast/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/@svgr/plugin-jsx": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", - "dev": true, "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", @@ -2905,7 +2522,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", - "dev": true, "dependencies": { "cosmiconfig": "^8.1.3", "deepmerge": "^4.3.1", @@ -2926,7 +2542,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", - "dev": true, "dependencies": { "@babel/core": "^7.21.3", "@babel/plugin-transform-react-constant-elements": "^7.21.3", @@ -2949,7 +2564,6 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", - "dev": true, "engines": { "node": ">=10.13.0" } @@ -3003,9 +2617,9 @@ } }, "node_modules/@types/eslint": { - "version": "8.56.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", - "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.0.tgz", + "integrity": "sha512-gi6WQJ7cHRgZxtkQEoyHMppPjq9Kxo5Tjn2prSKDSmZrCz8TZ3jSRCeTJm+WoM+oB0WG37bRqLzaaU3q7JypGg==", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -3088,9 +2702,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.14.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", - "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", + "version": "20.14.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz", + "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==", "dependencies": { "undici-types": "~5.26.4" } @@ -3192,25 +2806,25 @@ } }, "node_modules/@types/ws": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "version": "8.5.11", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.11.tgz", + "integrity": "sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.16.0.tgz", - "integrity": "sha512-py1miT6iQpJcs1BiJjm54AMzeuMPBSPuKPlnT8HlfudbcS5rYeX5jajpLf3mrdRh9dA/Ec2FVUY0ifeVNDIhZw==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.17.0.tgz", + "integrity": "sha512-pyiDhEuLM3PuANxH7uNYan1AaFs5XE0zw1hq69JBvGvE7gSuEoQl1ydtEe/XQeoC3GQxLXyOVa5kNOATgM638A==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.16.0", - "@typescript-eslint/type-utils": "7.16.0", - "@typescript-eslint/utils": "7.16.0", - "@typescript-eslint/visitor-keys": "7.16.0", + "@typescript-eslint/scope-manager": "7.17.0", + "@typescript-eslint/type-utils": "7.17.0", + "@typescript-eslint/utils": "7.17.0", + "@typescript-eslint/visitor-keys": "7.17.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -3233,16 +2847,17 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.16.0.tgz", - "integrity": "sha512-j0fuUswUjDHfqV/UdW6mLtOQQseORqfdmoBNDFOqs9rvNVR2e+cmu6zJu/Ku4SDuqiJko6YnhwcL8x45r8Oqxg==", + "node_modules/@typescript-eslint/parser": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.17.0.tgz", + "integrity": "sha512-puiYfGeg5Ydop8eusb/Hy1k7QmOU6X3nvsqCgzrB2K4qMavK//21+PzNE8qeECgNOIoertJPUC1SpegHDI515A==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.16.0", - "@typescript-eslint/utils": "7.16.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" + "@typescript-eslint/scope-manager": "7.17.0", + "@typescript-eslint/types": "7.17.0", + "@typescript-eslint/typescript-estree": "7.17.0", + "@typescript-eslint/visitor-keys": "7.17.0", + "debug": "^4.3.4" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -3260,16 +2875,14 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.0.tgz", - "integrity": "sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.17.0.tgz", + "integrity": "sha512-0P2jTTqyxWp9HiKLu/Vemr2Rg1Xb5B7uHItdVZ6iAenXmPo4SZ86yOPCJwMqpCyaMiEHTNqizHfsbmCFT1x9SA==", "dev": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.16.0", - "@typescript-eslint/types": "7.16.0", - "@typescript-eslint/typescript-estree": "7.16.0" + "@typescript-eslint/types": "7.17.0", + "@typescript-eslint/visitor-keys": "7.17.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -3277,45 +2890,18 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@typescript-eslint/parser": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.16.0.tgz", - "integrity": "sha512-ar9E+k7CU8rWi2e5ErzQiC93KKEFAXA2Kky0scAlPcxYblLt8+XZuHUZwlyfXILyQa95P6lQg+eZgh/dDs3+Vw==", + "node_modules/@typescript-eslint/type-utils": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.17.0.tgz", + "integrity": "sha512-XD3aaBt+orgkM/7Cei0XNEm1vwUxQ958AOLALzPlbPqb8C1G8PZK85tND7Jpe69Wualri81PLU+Zc48GVKIMMA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.16.0", - "@typescript-eslint/types": "7.16.0", - "@typescript-eslint/typescript-estree": "7.16.0", - "@typescript-eslint/visitor-keys": "7.16.0", - "debug": "^4.3.4" + "@typescript-eslint/typescript-estree": "7.17.0", + "@typescript-eslint/utils": "7.17.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -3333,50 +2919,10 @@ } } }, - "node_modules/@typescript-eslint/parser/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.16.0.tgz", - "integrity": "sha512-8gVv3kW6n01Q6TrI1cmTZ9YMFi3ucDT7i7aI5lEikk2ebk1AEjrwX8MDTdaX5D7fPXMBLvnsaa0IFTAu+jcfOw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.16.0", - "@typescript-eslint/visitor-keys": "7.16.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@typescript-eslint/types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.16.0.tgz", - "integrity": "sha512-fecuH15Y+TzlUutvUl9Cc2XJxqdLr7+93SQIbcZfd4XRGGKoxyljK27b+kxKamjRkU7FYC6RrbSCg0ALcZn/xw==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.17.0.tgz", + "integrity": "sha512-a29Ir0EbyKTKHnZWbNsrc/gqfIBqYPwj3F2M+jWE/9bqfEHg0AMtXzkbUkOG6QgEScxh2+Pz9OXe11jHDnHR7A==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -3387,13 +2933,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.16.0.tgz", - "integrity": "sha512-a5NTvk51ZndFuOLCh5OaJBELYc2O3Zqxfl3Js78VFE1zE46J2AaVuW+rEbVkQznjkmlzWsUI15BG5tQMixzZLw==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.17.0.tgz", + "integrity": "sha512-72I3TGq93t2GoSBWI093wmKo0n6/b7O4j9o8U+f65TVD0FS6bI2180X5eGEr8MA8PhKMvYe9myZJquUT2JkCZw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.16.0", - "@typescript-eslint/visitor-keys": "7.16.0", + "@typescript-eslint/types": "7.17.0", + "@typescript-eslint/visitor-keys": "7.17.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -3414,36 +2960,47 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.17.0.tgz", + "integrity": "sha512-r+JFlm5NdB+JXc7aWWZ3fKSm1gn0pkswEwIYsrGPdsT2GjsRATAKXiNtp3vgAAO1xZhX8alIOEQnNMl3kbTgJw==", "dev": true, "dependencies": { - "ms": "2.1.2" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.17.0", + "@typescript-eslint/types": "7.17.0", + "@typescript-eslint/typescript-estree": "7.17.0" }, "engines": { - "node": ">=6.0" + "node": "^18.18.0 || >=20.0.0" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.16.0.tgz", - "integrity": "sha512-rMo01uPy9C7XxG7AFsxa8zLnWXTF8N3PYclekWSrurvhwiw1eW88mrKiAYe6s53AUY57nTRz8dJsuuXdkAhzCg==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.17.0.tgz", + "integrity": "sha512-RVGC9UhPOCsfCdI9pU++K4nD7to+jTcMIbXTSOcrLqUEW6gF2pU1UUbYJKc9cvcRSK1UDeMJ7pdMxf4bhMpV/A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/types": "7.17.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -3713,15 +3270,15 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -3764,18 +3321,14 @@ } }, "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dependencies": { - "color-convert": "^2.0.1" + "color-convert": "^1.9.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=4" } }, "node_modules/anymatch": { @@ -3932,18 +3485,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array.prototype.toreversed": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", - "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - } - }, "node_modules/array.prototype.tosorted": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", @@ -4054,7 +3595,6 @@ "version": "0.4.11", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", - "dev": true, "dependencies": { "@babel/compat-data": "^7.22.6", "@babel/helper-define-polyfill-provider": "^0.6.2", @@ -4064,20 +3604,10 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/babel-plugin-polyfill-corejs3": { "version": "0.10.4", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz", "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==", - "dev": true, "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.1", "core-js-compat": "^3.36.1" @@ -4090,7 +3620,6 @@ "version": "0.6.2", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", - "dev": true, "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.2" }, @@ -4164,11 +3693,26 @@ "node": ">= 0.8" } }, - "node_modules/bonjour-service": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", - "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", - "dev": true, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/bonjour-service": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", + "dev": true, "dependencies": { "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" @@ -4301,7 +3845,6 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, "engines": { "node": ">=10" }, @@ -4310,9 +3853,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001642", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz", - "integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==", + "version": "1.0.30001643", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001643.tgz", + "integrity": "sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg==", "funding": [ { "type": "opencollective", @@ -4329,31 +3872,24 @@ ] }, "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=4" } }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, + "node_modules/chalk/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "engines": { - "node": ">=8" + "node": ">=0.8.0" } }, "node_modules/chokidar": { @@ -4380,6 +3916,18 @@ "fsevents": "~2.3.2" } }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/chrome-trace-event": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", @@ -4400,6 +3948,15 @@ "node": ">= 10.0" } }, + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -4415,22 +3972,17 @@ } }, "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "color-name": "1.1.3" } }, "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/colorette": { "version": "2.0.20", @@ -4439,9 +3991,13 @@ "dev": true }, "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } }, "node_modules/compressible": { "version": "2.0.18", @@ -4473,6 +4029,21 @@ "node": ">= 0.8.0" } }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, "node_modules/compression/node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -4539,7 +4110,6 @@ "version": "3.37.1", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", - "dev": true, "dependencies": { "browserslist": "^4.23.0" }, @@ -4628,6 +4198,18 @@ } } }, + "node_modules/css-loader/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/css-select": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", @@ -4648,7 +4230,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dev": true, "dependencies": { "mdn-data": "2.0.30", "source-map-js": "^1.0.1" @@ -4684,7 +4265,6 @@ "version": "5.0.5", "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", - "dev": true, "dependencies": { "css-tree": "~2.2.0" }, @@ -4697,7 +4277,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", - "dev": true, "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" @@ -4710,8 +4289,7 @@ "node_modules/csso/node_modules/mdn-data": { "version": "2.0.28", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", - "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", - "dev": true + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==" }, "node_modules/csstype": { "version": "3.1.3", @@ -4776,12 +4354,19 @@ } }, "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dependencies": { - "ms": "2.0.0" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/deep-equal": { @@ -4816,12 +4401,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/deep-equal/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -5006,6 +4585,15 @@ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/domelementtype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", @@ -5056,11 +4644,15 @@ } }, "node_modules/dotenv": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", - "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "dev": true, "engines": { - "node": ">=10" + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" } }, "node_modules/dotenv-defaults": { @@ -5071,6 +4663,14 @@ "dotenv": "^8.2.0" } }, + "node_modules/dotenv-defaults/node_modules/dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "engines": { + "node": ">=10" + } + }, "node_modules/dotenv-webpack": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/dotenv-webpack/-/dotenv-webpack-8.1.0.tgz", @@ -5098,9 +4698,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.827", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.827.tgz", - "integrity": "sha512-VY+J0e4SFcNfQy19MEoMdaIcZLmDCprqvBtkii1WTCTQHpRvf5N8+3kTYCgL/PcntvwQvmMJWTuDPsq+IlhWKQ==" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.0.tgz", + "integrity": "sha512-Vb3xHHYnLseK8vlMJQKJYXJ++t4u1/qJ3vykuVrVjvdiOEhYyT1AuP4x03G8EnPmYvYOhe9T+dADTmthjRQMkA==" }, "node_modules/emoji-regex": { "version": "9.2.2", @@ -5127,9 +4727,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", - "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -5139,10 +4739,12 @@ } }, "node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true, + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } @@ -5268,12 +4870,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es-get-iterator/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, "node_modules/es-iterator-helpers": { "version": "1.0.19", "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", @@ -5371,24 +4967,27 @@ "dev": true }, "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "engines": { - "node": ">=0.8.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.6.0.tgz", - "integrity": "sha512-ElQkdLMEEqQNM9Njff+2Y4q2afHk7JpkPvrd7Xh7xefwgQynqPxwf55J7di9+MEibWUGdNjFF9ITG9Pck5M84w==", + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.7.0.tgz", + "integrity": "sha512-FzJ9D/0nGiCGBf8UXO/IGLTgLVzIxze1zpfA8Ton2mjLovXdAPlYDv+MQDcqj3TmrhAGYfOpz9RfR+ent0AgAw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", + "@eslint-community/regexpp": "^4.11.0", "@eslint/config-array": "^0.17.0", "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.6.0", + "@eslint/js": "9.7.0", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.3.0", "@nodelib/fs.walk": "^1.2.8", @@ -5397,7 +4996,7 @@ "cross-spawn": "^7.0.2", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.0.1", + "eslint-scope": "^8.0.2", "eslint-visitor-keys": "^4.0.0", "espree": "^10.1.0", "esquery": "^1.5.0", @@ -5449,12 +5048,6 @@ "ms": "^2.1.1" } }, - "node_modules/eslint-import-resolver-node/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, "node_modules/eslint-import-resolver-typescript": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", @@ -5480,29 +5073,6 @@ "eslint-plugin-import": "*" } }, - "node_modules/eslint-import-resolver-typescript/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/eslint-import-resolver-typescript/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/eslint-module-utils": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", @@ -5529,12 +5099,6 @@ "ms": "^2.1.1" } }, - "node_modules/eslint-module-utils/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, "node_modules/eslint-plugin-import": { "version": "2.29.1", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", @@ -5597,21 +5161,6 @@ "node": "*" } }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/eslint-plugin-jsx-a11y": { "version": "6.9.0", "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.9.0.tgz", @@ -5665,13 +5214,13 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", - "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", + "integrity": "sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==", "dev": true, "dependencies": { "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.8.6" + "synckit": "^0.9.1" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -5695,35 +5244,35 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.34.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.3.tgz", - "integrity": "sha512-aoW4MV891jkUulwDApQbPYTVZmeuSyFrudpbTAQuj5Fv8VL+o6df2xIGpw8B0hPjAaih1/Fb0om9grCdyFYemA==", + "version": "7.35.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.35.0.tgz", + "integrity": "sha512-v501SSMOWv8gerHkk+IIQBkcGRGrO2nfybfj5pLxuJNFTPxxA3PSryhXTK+9pNbtkggheDdsC0E9Q8CuPk6JKA==", "dev": true, "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.2", - "array.prototype.toreversed": "^1.1.2", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", "es-iterator-helpers": "^1.0.19", "estraverse": "^5.3.0", + "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.8", "object.fromentries": "^2.0.8", - "object.hasown": "^1.1.4", "object.values": "^1.2.0", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.11" + "string.prototype.matchall": "^4.0.11", + "string.prototype.repeat": "^1.0.0" }, "engines": { "node": ">=4" }, "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "node_modules/eslint-plugin-react-hooks": { @@ -5748,15 +5297,6 @@ "concat-map": "0.0.1" } }, - "node_modules/eslint-plugin-react/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/eslint-plugin-react/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -5786,25 +5326,20 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint-plugin-react/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/eslint-scope": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", + "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dependencies": { "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "estraverse": "^5.2.0" }, "engines": { - "node": ">=8.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { @@ -5819,6 +5354,21 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -5829,51 +5379,40 @@ "concat-map": "0.0.1" } }, - "node_modules/eslint/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "ms": "2.1.2" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.1.tgz", - "integrity": "sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==", + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "color-name": "~1.1.4" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=7.0.0" } }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "node_modules/eslint/node_modules/eslint-visitor-keys": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", @@ -5886,56 +5425,13 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/eslint/node_modules/minimatch": { @@ -5950,40 +5446,16 @@ "node": "*" } }, - "node_modules/eslint/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "p-limit": "^3.0.2" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/espree": { @@ -6027,15 +5499,6 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -6047,7 +5510,7 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", @@ -6055,14 +5518,6 @@ "node": ">=4.0" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "engines": { - "node": ">=4.0" - } - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -6159,6 +5614,21 @@ "node": ">= 0.10.0" } }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -6186,6 +5656,18 @@ "node": ">=8.6.0" } }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -6275,22 +5757,40 @@ "node": ">= 0.8" } }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, "node_modules/find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" }, "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "dependencies": { - "locate-path": "^5.0.0", + "locate-path": "^6.0.0", "path-exists": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/flat": { @@ -6406,6 +5906,21 @@ "webpack": "^5.11.0" } }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -6416,16 +5931,47 @@ "concat-map": "0.0.1" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/memfs": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", - "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "fs-monkey": "^1.0.4" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">= 4.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" } }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/minimatch": { @@ -6440,6 +5986,30 @@ "node": "*" } }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -6531,7 +6101,6 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -6617,15 +6186,15 @@ } }, "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "dependencies": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 6" + "node": ">=10.13.0" } }, "node_modules/glob-to-regexp": { @@ -6705,9 +6274,9 @@ "dev": true }, "node_modules/haengdong-design": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/haengdong-design/-/haengdong-design-0.1.3.tgz", - "integrity": "sha512-l/ED7kcE/LAZkuXxEFDU0j5k7Bac+t4dTJIxAAH8Ij9byaxdblzJF4DiRQ10AZ2RfuDzHYuI5MULq+18sU2cXA==", + "version": "0.1.20", + "resolved": "https://registry.npmjs.org/haengdong-design/-/haengdong-design-0.1.20.tgz", + "integrity": "sha512-MB4L5lP0eDKhm5hU/XROKNE/H0pj9Zaf/uiLUUhtvOzS6bzHd2guYlE/LI0G2bvA7v65APD1Bzp3KXGi/Z8nNw==", "dependencies": { "@emotion/react": "^11.11.4", "@svgr/webpack": "^8.1.0", @@ -6736,11 +6305,11 @@ } }, "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/has-property-descriptors": { @@ -6834,6 +6403,12 @@ "wbuf": "^1.1.0" } }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, "node_modules/hpack.js/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", @@ -6900,28 +6475,7 @@ "webpack": "^5.0.0" } }, - "node_modules/html-loader/node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "dev": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/html-loader/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/html-loader/node_modules/html-minifier-terser": { + "node_modules/html-minifier-terser": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", @@ -6942,36 +6496,6 @@ "node": "^14.13.1 || >=16.0.0" } }, - "node_modules/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", - "dev": true, - "dependencies": { - "camel-case": "^4.1.2", - "clean-css": "^5.2.2", - "commander": "^8.3.0", - "he": "^1.2.0", - "param-case": "^3.0.4", - "relateurl": "^0.2.7", - "terser": "^5.10.0" - }, - "bin": { - "html-minifier-terser": "cli.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/html-minifier-terser/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, "node_modules/html-webpack-plugin": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", @@ -7004,6 +6528,36 @@ } } }, + "node_modules/html-webpack-plugin/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/html-webpack-plugin/node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/htmlparser2": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", @@ -7023,6 +6577,15 @@ "entities": "^2.0.0" } }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/http-deceiver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", @@ -7155,18 +6718,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "engines": { - "node": ">=4" - } - }, "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, "dependencies": { "pkg-dir": "^4.2.0", @@ -7334,9 +6889,9 @@ } }, "node_modules/is-core-module": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", - "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", + "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", "dependencies": { "hasown": "^2.0.2" }, @@ -7716,9 +7271,9 @@ } }, "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true }, "node_modules/isexe": { @@ -7777,6 +7332,28 @@ "node": ">= 10.13.0" } }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -7827,15 +7404,14 @@ "dev": true }, "node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "bin": { "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" } }, "node_modules/jsonfile": { @@ -7943,37 +7519,28 @@ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/loader-utils-webpack-v4/node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" }, "engines": { - "node": ">=6" + "node": ">=8.9.0" } }, "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "dependencies": { - "p-locate": "^4.1.0" + "p-locate": "^5.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/lodash": { @@ -7985,8 +7552,7 @@ "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -8014,16 +7580,17 @@ } }, "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } }, "node_modules/mdn-data": { "version": "2.0.30", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" }, "node_modules/media-typer": { "version": "0.3.0", @@ -8035,22 +7602,15 @@ } }, "node_modules/memfs": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.9.3.tgz", - "integrity": "sha512-bsYSSnirtYTWi1+OPMFb0M048evMKyUYe0EbtuGQgq6BVQM1g1W8/KIUJCCvjgI/El0j6Q4WsmMiBwLUBSw8LA==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", "dev": true, "dependencies": { - "@jsonjoy.com/json-pack": "^1.0.3", - "@jsonjoy.com/util": "^1.1.2", - "tree-dump": "^1.0.1", - "tslib": "^2.0.0" + "fs-monkey": "^1.0.4" }, "engines": { "node": ">= 4.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" } }, "node_modules/merge-descriptors": { @@ -8241,10 +7801,9 @@ } }, "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/multicast-dns": { "version": "7.2.5", @@ -8322,9 +7881,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -8468,23 +8027,6 @@ "node": ">= 0.4" } }, - "node_modules/object.hasown": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", - "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/object.values": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", @@ -8580,30 +8122,33 @@ } }, "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "dependencies": { - "p-try": "^2.0.0" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">=6" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "dependencies": { - "p-limit": "^2.2.0" + "p-limit": "^3.0.2" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-retry": { @@ -8688,18 +8233,6 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/parse5/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -8758,6 +8291,12 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -8801,6 +8340,58 @@ "node": ">=8" } }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/possible-typed-array-names": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", @@ -9114,11 +8705,11 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/react-router": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.24.1.tgz", - "integrity": "sha512-PTXFXGK2pyXpHzVo3rR9H7ip4lSPZZc0bHG5CARmj65fTT6qG7sTngmb6lcYu1gf3y/8KxORoy9yn59pGpCnpg==", + "version": "6.25.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.25.1.tgz", + "integrity": "sha512-u8ELFr5Z6g02nUtpPAggP73Jigj1mRePSwhS/2nkTrlPU5yEkH1vYzWNyvSnSzeeE2DNqWdH+P8OhIh9wuXhTw==", "dependencies": { - "@remix-run/router": "1.17.1" + "@remix-run/router": "1.18.0" }, "engines": { "node": ">=14.0.0" @@ -9128,12 +8719,12 @@ } }, "node_modules/react-router-dom": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.24.1.tgz", - "integrity": "sha512-U19KtXqooqw967Vw0Qcn5cOvrX5Ejo9ORmOtJMzYWtCT4/WOfFLIZGGsVLxcd9UkBO0mSTZtXqhZBsWlHr7+Sg==", + "version": "6.25.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.25.1.tgz", + "integrity": "sha512-0tUDpbFvk35iv+N89dWNrJp+afLgd+y4VtorJZuOCXK0kkCWjEvb3vTJM++SYvMEpbVwXKf3FjeVveVEb6JpDQ==", "dependencies": { - "@remix-run/router": "1.17.1", - "react-router": "6.24.1" + "@remix-run/router": "1.18.0", + "react-router": "6.25.1" }, "engines": { "node": ">=14.0.0" @@ -9205,14 +8796,12 @@ "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" }, "node_modules/regenerate-unicode-properties": { "version": "10.1.1", "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", - "dev": true, "dependencies": { "regenerate": "^1.4.2" }, @@ -9229,7 +8818,6 @@ "version": "0.15.2", "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", - "dev": true, "dependencies": { "@babel/runtime": "^7.8.4" } @@ -9256,7 +8844,6 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", - "dev": true, "dependencies": { "@babel/regjsgen": "^0.8.0", "regenerate": "^1.4.2", @@ -9273,7 +8860,6 @@ "version": "0.9.1", "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", - "dev": true, "dependencies": { "jsesc": "~0.5.0" }, @@ -9285,7 +8871,6 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "dev": true, "bin": { "jsesc": "bin/jsesc" } @@ -9355,7 +8940,7 @@ "node": ">=8" } }, - "node_modules/resolve-from": { + "node_modules/resolve-cwd/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", @@ -9364,6 +8949,14 @@ "node": ">=8" } }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", @@ -9463,12 +9056,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/safe-array-concat/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -9556,15 +9143,11 @@ } }, "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true, + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" } }, "node_modules/send": { @@ -9591,6 +9174,21 @@ "node": ">= 0.8.0" } }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -9623,6 +9221,15 @@ "node": ">= 0.8.0" } }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, "node_modules/serve-index/node_modules/depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -9653,6 +9260,12 @@ "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", "dev": true }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, "node_modules/serve-index/node_modules/setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", @@ -9800,7 +9413,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", - "dev": true, "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" @@ -9818,9 +9430,9 @@ } }, "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "engines": { "node": ">=0.10.0" } @@ -9842,6 +9454,14 @@ "source-map": "^0.6.0" } }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/spdy": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", @@ -9861,63 +9481,17 @@ "node_modules/spdy-transport": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "dev": true, - "dependencies": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - } - }, - "node_modules/spdy-transport/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/spdy-transport/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/spdy/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "dev": true, "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" } }, - "node_modules/spdy/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -10049,6 +9623,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, "node_modules/string.prototype.trim": { "version": "1.2.9", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", @@ -10175,17 +9759,14 @@ "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" }, "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dependencies": { - "has-flag": "^4.0.0" + "has-flag": "^3.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "node": ">=4" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -10202,14 +9783,12 @@ "node_modules/svg-parser": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", - "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", - "dev": true + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" }, "node_modules/svgo": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", - "dev": true, "dependencies": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", @@ -10234,7 +9813,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true, "engines": { "node": ">= 10" } @@ -10243,7 +9821,6 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "dev": true, "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -10259,7 +9836,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -10273,7 +9849,6 @@ "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, "dependencies": { "domelementtype": "^2.3.0" }, @@ -10288,7 +9863,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "dev": true, "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", @@ -10298,22 +9872,10 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "node_modules/svgo/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/synckit": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", - "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", + "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", "dev": true, "dependencies": { "@pkgr/core": "^0.1.0", @@ -10335,9 +9897,9 @@ } }, "node_modules/terser": { - "version": "5.31.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.2.tgz", - "integrity": "sha512-LGyRZVFm/QElZHy/CPr/O4eNZOZIzsrQ92y4v9UJe/pFJjypje2yI3C2FmPtvUEnhadlSbmG2nXtdcjHOjCfxw==", + "version": "5.31.3", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.3.tgz", + "integrity": "sha512-pAfYn3NIZLyZpa83ZKigvj6Rn9c/vd5KfYGX7cN1mnzqgDcxWvrU5ZtAfIKhEXz9nRecw4z3LXkjaq96/qZqAA==", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -10384,6 +9946,11 @@ } } }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -10485,6 +10052,76 @@ "webpack": "^5.0.0" } }, + "node_modules/ts-loader/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ts-loader/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ts-loader/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ts-loader/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/ts-loader/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-loader/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/ts-loader/node_modules/source-map": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", @@ -10494,6 +10131,18 @@ "node": ">= 8" } }, + "node_modules/ts-loader/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -10506,6 +10155,18 @@ "strip-bom": "^3.0.0" } }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, "node_modules/tslib": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", @@ -10610,9 +10271,9 @@ } }, "node_modules/typescript": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", - "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -10623,14 +10284,14 @@ } }, "node_modules/typescript-eslint": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.16.0.tgz", - "integrity": "sha512-kaVRivQjOzuoCXU6+hLnjo3/baxyzWVO5GrnExkFzETRYJKVHYkrJglOu2OCm8Hi9RPDWX1PTNNTpU5KRV0+RA==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.17.0.tgz", + "integrity": "sha512-spQxsQvPguduCUfyUvLItvKqK3l8KJ/kqs5Pb/URtzQ5AC53Z6us32St37rpmlt2uESG23lOFpV4UErrmy4dZQ==", "dev": true, "dependencies": { - "@typescript-eslint/eslint-plugin": "7.16.0", - "@typescript-eslint/parser": "7.16.0", - "@typescript-eslint/utils": "7.16.0" + "@typescript-eslint/eslint-plugin": "7.17.0", + "@typescript-eslint/parser": "7.17.0", + "@typescript-eslint/utils": "7.17.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -10648,28 +10309,6 @@ } } }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.0.tgz", - "integrity": "sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.16.0", - "@typescript-eslint/types": "7.16.0", - "@typescript-eslint/typescript-estree": "7.16.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - } - }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -10688,14 +10327,12 @@ "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "dev": true, "engines": { "node": ">=4" } @@ -10704,7 +10341,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", "unicode-property-aliases-ecmascript": "^2.0.0" @@ -10717,7 +10353,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", - "dev": true, "engines": { "node": ">=4" } @@ -10726,7 +10361,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", - "dev": true, "engines": { "node": ">=4" } @@ -10937,19 +10571,10 @@ } } }, - "node_modules/webpack-cli/node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "dev": true, - "engines": { - "node": ">=14" - } - }, "node_modules/webpack-dev-middleware": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.2.1.tgz", - "integrity": "sha512-hRLz+jPQXo999Nx9fXVdKlg/aehsw1ajA9skAneGmT03xwmyuhvF93p6HUKKbWhXdcERtGTzUCtIQr+2IQegrA==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.3.0.tgz", + "integrity": "sha512-xD2qnNew+F6KwOGZR7kWdbIou/ud7cVqLEXeK1q0nHcNsX/u7ul/fSdlOTX4ntSL5FNFy7ZJJXbf0piF591JYw==", "dev": true, "dependencies": { "colorette": "^2.0.10", @@ -10976,15 +10601,15 @@ } }, "node_modules/webpack-dev-middleware/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -11009,6 +10634,25 @@ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, + "node_modules/webpack-dev-middleware/node_modules/memfs": { + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.9.3.tgz", + "integrity": "sha512-bsYSSnirtYTWi1+OPMFb0M048evMKyUYe0EbtuGQgq6BVQM1g1W8/KIUJCCvjgI/El0j6Q4WsmMiBwLUBSw8LA==", + "dev": true, + "dependencies": { + "@jsonjoy.com/json-pack": "^1.0.3", + "@jsonjoy.com/util": "^1.1.2", + "tree-dump": "^1.0.1", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">= 4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + } + }, "node_modules/webpack-dev-middleware/node_modules/schema-utils": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", @@ -11088,15 +10732,15 @@ } }, "node_modules/webpack-dev-server/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -11162,6 +10806,26 @@ "node": ">=10.13.0" } }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, "node_modules/websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", @@ -11242,12 +10906,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/which-builtin-type/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, "node_modules/which-collection": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", @@ -11335,6 +10993,39 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -11418,8 +11109,7 @@ "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/yaml": { "version": "1.10.2", @@ -11442,4 +11132,4 @@ } } } -} \ No newline at end of file +} diff --git a/client/package.json b/client/package.json index f25247dc3..8155d4dc9 100644 --- a/client/package.json +++ b/client/package.json @@ -21,6 +21,7 @@ "@typescript-eslint/eslint-plugin": "^7.16.0", "@typescript-eslint/parser": "^7.16.0", "css-loader": "^7.1.2", + "dotenv": "^16.4.5", "eslint": "^9.6.0", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.29.1", @@ -44,9 +45,9 @@ }, "dependencies": { "@emotion/react": "^11.11.4", + "haengdong-design": "^0.1.20", "@types/dotenv-webpack": "^7.0.7", "dotenv-webpack": "^8.1.0", - "haengdong-design": "^0.1.3", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.24.1" diff --git a/client/src/apis/baseUrl.ts b/client/src/apis/baseUrl.ts new file mode 100644 index 000000000..e508ba375 --- /dev/null +++ b/client/src/apis/baseUrl.ts @@ -0,0 +1,3 @@ +export const BASE_URL = { + HD: process.env.API_BASE_URL ?? '', +}; diff --git a/client/src/apis/request/bill.ts b/client/src/apis/request/bill.ts new file mode 100644 index 000000000..31c097276 --- /dev/null +++ b/client/src/apis/request/bill.ts @@ -0,0 +1,19 @@ +import {BASE_URL} from '@apis/baseUrl'; +import {TEMP_PREFIX} from '@apis/tempPrefix'; +import {requestPost} from '@apis/fetcher'; +import {WithEventId} from '@apis/withEventId.type'; +import {Bill} from 'types/stepList'; + +type RequestAddBillList = { + BillList: Bill[]; +}; + +export const requestAddBillList = async ({eventId, BillList}: WithEventId<RequestAddBillList>) => { + await requestPost({ + baseUrl: BASE_URL.HD, + endpoint: `${TEMP_PREFIX}/${eventId}/actions/bills`, + body: { + actions: BillList, + }, + }); +}; diff --git a/client/src/apis/request/event.ts b/client/src/apis/request/event.ts new file mode 100644 index 000000000..c941f31d4 --- /dev/null +++ b/client/src/apis/request/event.ts @@ -0,0 +1,17 @@ +import {BASE_URL} from '@apis/baseUrl'; +import {TEMP_PREFIX} from '@apis/tempPrefix'; +import {requestGet} from '@apis/fetcher'; +import {StepList} from 'types/stepList'; + +type RequestCreateNewEvent = { + name: string; +}; + +export const requestCreateNewEvent = async ({name}: RequestCreateNewEvent) => { + // TODO: (@weadie) 뼈대만 둔 것. header값을 꺼내오는 로직이 필요하다. 또는 바디에 달라고 부탁할 수 있다. + return await requestGet<StepList>({ + baseUrl: BASE_URL.HD, + endpoint: TEMP_PREFIX, + body: {name}, + }); +}; diff --git a/client/src/apis/request/member.ts b/client/src/apis/request/member.ts new file mode 100644 index 000000000..af8b6c689 --- /dev/null +++ b/client/src/apis/request/member.ts @@ -0,0 +1,19 @@ +import {BASE_URL} from '@apis/baseUrl'; +import {TEMP_PREFIX} from '@apis/tempPrefix'; +import {requestPost} from '@apis/fetcher'; +import {WithEventId} from '@apis/withEventId.type'; +import {Member} from 'types/stepList'; + +type RequestUpdateMemberList = { + MemberList: Member[]; +}; + +export const requestUpdateMemberList = async ({eventId, MemberList}: WithEventId<RequestUpdateMemberList>) => { + await requestPost({ + baseUrl: BASE_URL.HD, + endpoint: `${TEMP_PREFIX}/${eventId}/actions/members`, + body: { + actions: MemberList, + }, + }); +}; diff --git a/client/src/apis/request/report.ts b/client/src/apis/request/report.ts new file mode 100644 index 000000000..cc9b0ad66 --- /dev/null +++ b/client/src/apis/request/report.ts @@ -0,0 +1,18 @@ +import {BASE_URL} from '@apis/baseUrl'; +import {TEMP_PREFIX} from '@apis/tempPrefix'; +import {requestGet} from '@apis/fetcher'; +import {WithEventId} from '@apis/withEventId.type'; +import {MemberReport} from 'types/stepList'; + +type ResponseMemberReportList = { + reports: MemberReport[]; +}; + +export const requestMemberReportList = async ({eventId}: WithEventId) => { + const {reports} = await requestGet<ResponseMemberReportList>({ + baseUrl: BASE_URL.HD, + endpoint: `${TEMP_PREFIX}/${eventId}/actions`, + }); + + return reports; +}; diff --git a/client/src/apis/request/stepList.ts b/client/src/apis/request/stepList.ts new file mode 100644 index 000000000..d696c69aa --- /dev/null +++ b/client/src/apis/request/stepList.ts @@ -0,0 +1,14 @@ +import {BASE_URL} from '@apis/baseUrl'; +import {TEMP_PREFIX} from '@apis/tempPrefix'; +import {requestGet, requestPost} from '@apis/fetcher'; +import {WithEventId} from '@apis/withEventId.type'; +import {Bill, Member, StepList} from 'types/stepList'; + +// TODO: (@weadie) 현재 토큰을 어떻게 관리할지.. 계속 사용되는데 +export const requestStepList = async ({eventId}: WithEventId) => { + // TODO: (@weadie) response가 어떻게 오는지 안나와서 data로만 써뒀어요. + return await requestGet<StepList>({ + baseUrl: BASE_URL.HD, + endpoint: `${TEMP_PREFIX}/${eventId}/actions`, + }); +}; diff --git a/client/src/apis/tempPrefix.ts b/client/src/apis/tempPrefix.ts new file mode 100644 index 000000000..949981b73 --- /dev/null +++ b/client/src/apis/tempPrefix.ts @@ -0,0 +1,2 @@ +// TODO: (@weadie) 반복되서 쓰이는 이 api/events가 추후 수정 가능성이 있어서 일단 편집하기 편하게 이 변수를 재사용하도록 했습니다. +export const TEMP_PREFIX = '/api/events'; diff --git a/client/src/apis/withEventId.type.ts b/client/src/apis/withEventId.type.ts new file mode 100644 index 000000000..b88160e3e --- /dev/null +++ b/client/src/apis/withEventId.type.ts @@ -0,0 +1,3 @@ +export type WithEventId<P = unknown> = P & { + eventId: string; +}; diff --git a/client/src/components/MemberReportList/MemberReportList.tsx b/client/src/components/MemberReportList/MemberReportList.tsx new file mode 100644 index 000000000..17a26f9ca --- /dev/null +++ b/client/src/components/MemberReportList/MemberReportList.tsx @@ -0,0 +1,21 @@ +import useSearchMemberReportList from '@hooks/useSearchMemberReportList/useSearchMemberReportList'; +import {ExpenseList, Flex, Input} from 'haengdong-design'; +import React, {useState} from 'react'; + +const MemberReportList = () => { + const [name, setName] = useState(''); + const {memberReportSearchList} = useSearchMemberReportList({name, eventId: '므와아아아'}); + + const changeName = ({target}: React.ChangeEvent<HTMLInputElement>) => { + setName(target.value); + }; + + return ( + <Flex flexDirection="column" gap="0.5rem" paddingInline="0.5rem" padding="1rem 0 0 0"> + <Input inputType="search" value={name} onChange={changeName} /> + <ExpenseList expenseList={memberReportSearchList} /> + </Flex> + ); +}; + +export default MemberReportList; diff --git a/client/src/components/StepList/StepList.tsx b/client/src/components/StepList/StepList.tsx new file mode 100644 index 000000000..2ea9c0bc5 --- /dev/null +++ b/client/src/components/StepList/StepList.tsx @@ -0,0 +1,24 @@ +import {useStepList} from '@hooks/useStepList/useStepList'; +import {Flex, InOutItem, StepItem} from 'haengdong-design'; +import {MemberType} from 'types/stepList'; + +const StepList = () => { + const {stepList} = useStepList(); + + // TODO: (@weadie) if else 구문이 지저분하므로 리펙터링이 필요합니다. + return ( + <Flex flexDirection="column" gap="0.5rem" paddingInline="0.5rem" padding="1rem 0 0 0"> + {stepList.map(step => { + if (step.type === 'BILL') { + return <StepItem name={step.stepName} bills={step.actions} personCount={0} />; + } else if (step.type === 'IN' || step.type === 'OUT') { + return <InOutItem inOutType={step.type} names={step.actions.map(({name}) => name)} />; + } else { + return <></>; + } + })} + </Flex> + ); +}; + +export default StepList; diff --git a/client/src/constants/routerUrls.ts b/client/src/constants/routerUrls.ts index eb4f6938b..f0a910d5b 100644 --- a/client/src/constants/routerUrls.ts +++ b/client/src/constants/routerUrls.ts @@ -4,4 +4,5 @@ export const ROUTER_URLS = { eventCreateComplete: '/event/create/complete', event: '/event', eventManage: '/event/:eventId', + home: '/event/:eventId/home', }; diff --git a/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.tsx b/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.tsx new file mode 100644 index 000000000..bdd1e3cf2 --- /dev/null +++ b/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.tsx @@ -0,0 +1,42 @@ +import {useEffect, useState} from 'react'; +import {MemberReport} from 'types/stepList'; +import memberReportSearchJsonList from '@mocks/memberReportSearchList.json'; +import {requestMemberReportList} from '@apis/request/report'; +import {WithEventId} from '@apis/withEventId.type'; + +const memberReportSearchMockList = memberReportSearchJsonList as MemberReport[]; + +type UseSearchMemberReportListParams = { + name: string; +}; + +const useSearchMemberReportList = ({name, eventId}: WithEventId<UseSearchMemberReportListParams>) => { + const [memberReportList, setMemberReportList] = useState<MemberReport[]>(memberReportSearchMockList); + const [memberReportSearchList, setMemberReportSearchList] = useState<MemberReport[]>([]); + + useEffect(() => { + const fetchMemberReportList = async () => { + // TODO: (@weadie) cors 고쳐지면 주석 풀게요. + // const memberReportListData = await requestMemberReportList({eventId}); + + const memberReportListData = memberReportSearchMockList; + + setMemberReportList(memberReportListData); + }; + + fetchMemberReportList(); + }, []); + + // TODO: (@weadie) 글자가 완성될 때마다 아래 로직이 실행되어야 합니다. + useEffect(() => { + if (name === '') setMemberReportSearchList(memberReportList); + + setMemberReportSearchList(memberReportList.filter(memberReport => memberReport.name.includes(name))); + }, [name]); + + return { + memberReportSearchList, + }; +}; + +export default useSearchMemberReportList; diff --git a/client/src/hooks/useStepList/useStepList.tsx b/client/src/hooks/useStepList/useStepList.tsx new file mode 100644 index 000000000..842794f0f --- /dev/null +++ b/client/src/hooks/useStepList/useStepList.tsx @@ -0,0 +1,47 @@ +import {PropsWithChildren, createContext, useEffect, useState} from 'react'; +import {BillAction, MemberType, StepList} from 'types/stepList'; +import stepListJsonData from '@mocks/stepList.json'; + +const stepListMockData = stepListJsonData as StepList; + +const useStepList = () => { + const [stepList, setStepList] = useState<StepList>(stepListMockData); + + useEffect(() => { + // TODO: (@weadie) useEffect를 꼭 써야하는가? + // 초기 리스트 불러서 setActionList + }, []); + + const updateMemberList = (type: MemberType, memberList: string[]) => { + // api를 호출하고 set한다 + }; + + const addBill = (title: string, price: number) => { + // api를 호출하고 set한다. + }; + + const calculateBillSum = (actions: BillAction[]) => { + return actions.reduce((sum, {price}) => sum + price, 0); + }; + + const getTotalPrice = () => { + return stepList.reduce((sum, {type, actions}) => { + if (type === 'BILL') { + return sum + calculateBillSum(actions); + } + return sum; + }, 0); + }; + + return {stepList, getTotalPrice}; +}; + +const StepListContext = createContext<StepList>([]); // TODO: (@weadie) 인자를 어떻게 줘야 하는지 고민하기. + +const StepListProvider = ({children}: PropsWithChildren) => { + const {stepList} = useStepList(); + + return <StepListContext.Provider value={stepList}>{children}</StepListContext.Provider>; +}; + +export {useStepList, StepListProvider}; diff --git a/client/src/mocks/memberReportSearchList.json b/client/src/mocks/memberReportSearchList.json new file mode 100644 index 000000000..dfcb684b1 --- /dev/null +++ b/client/src/mocks/memberReportSearchList.json @@ -0,0 +1,10 @@ +[ + {"name": "망쵸", "price": 1033200}, + {"name": "이상", "price": 10100}, + {"name": "소하", "price": 10000}, + {"name": "쿠키", "price": 100012}, + {"name": "토다리", "price": 1001230}, + {"name": "감자", "price": 1012300}, + {"name": "백호", "price": 10300}, + {"name": "웨디", "price": 1000} +] diff --git a/client/src/mocks/stepList.json b/client/src/mocks/stepList.json new file mode 100644 index 000000000..cc3815a75 --- /dev/null +++ b/client/src/mocks/stepList.json @@ -0,0 +1,86 @@ +[ + { + "type": "IN", + "stepName": null, + "actions": [ + { + "actionId": 3, + "name": "망쵸", + "price": null, + "sequence": 3 + }, + { + "actionId": 4, + "name": "백호", + "price": null, + "sequence": 4 + } + ] + }, + { + "type": "BILL", + "stepName": "1차", + "actions": [ + { + "actionId": 1, + "name": "감자탕", + "price": 10000, + "sequence": 1 + }, + { + "actionId": 2, + "name": "인생네컷", + "price": 10000, + "sequence": 2 + } + ] + }, + { + "type": "IN", + "stepName": null, + "actions": [ + { + "actionId": 3, + "name": "망쵸", + "price": null, + "sequence": 3 + }, + { + "actionId": 4, + "name": "백호", + "price": null, + "sequence": 4 + } + ] + }, + { + "type": "OUT", + "stepName": null, + "actions": [ + { + "actionId": 5, + "name": "소하", + "price": null, + "sequence": 5 + }, + { + "actionId": 6, + "name": "웨디", + "price": null, + "sequence": 6 + } + ] + }, + { + "type": "BILL", + "stepName": "2차", + "actions": [ + { + "actionId": 8, + "name": "노래방", + "price": 20000, + "sequence": 7 + } + ] + } +] diff --git a/client/src/pages/CreateEvent/CreateEvent.tsx b/client/src/pages/CreateEvent/CreateEvent.tsx new file mode 100644 index 000000000..eb25c1faf --- /dev/null +++ b/client/src/pages/CreateEvent/CreateEvent.tsx @@ -0,0 +1,26 @@ +import {useState} from 'react'; +import {useNavigate} from 'react-router-dom'; +import {ROUTER_URLS} from '@constants/routerUrls'; + +const CreateEvent = () => { + const [eventTitle, setEventTitle] = useState(''); + const navigate = useNavigate(); + + const submitEventTitle = (event: React.FormEvent<HTMLFormElement>) => { + event.preventDefault(); + navigate(`${ROUTER_URLS.eventCreateName}?${new URLSearchParams({title: eventTitle})}`); + }; + + return ( + <section> + <h1>행사 생성하기</h1> + <h3>시작할 행사 이름을 입력해 주세요.</h3> + <form onSubmit={submitEventTitle}> + <input value={eventTitle} onChange={event => setEventTitle(event.target.value)} /> + <button>행동 개시!</button> + </form> + </section> + ); +}; + +export default CreateEvent; diff --git a/client/src/pages/Home/HomeContent.tsx b/client/src/pages/Home/HomeContent.tsx new file mode 100644 index 000000000..c13829222 --- /dev/null +++ b/client/src/pages/Home/HomeContent.tsx @@ -0,0 +1,20 @@ +import MemberReportList from '@components/MemberReportList/MemberReportList'; +import StepList from '@components/StepList/StepList'; +import {useStepList} from '@hooks/useStepList/useStepList'; +import {Tab, Tabs, Title} from 'haengdong-design'; + +const HomeContent = () => { + const {getTotalPrice} = useStepList(); + + return ( + <div> + <Title title="행동대장 야유회" price={getTotalPrice()} /> + <Tabs> + <Tab label="전체 지출 내역" content={<StepList />} /> + <Tab label="참여자 별 내역" content={<MemberReportList />} /> + </Tabs> + </div> + ); +}; + +export default HomeContent; diff --git a/client/src/pages/Home/HomeLayout.tsx b/client/src/pages/Home/HomeLayout.tsx new file mode 100644 index 000000000..c204f3da1 --- /dev/null +++ b/client/src/pages/Home/HomeLayout.tsx @@ -0,0 +1,19 @@ +import {Flex, MainLayout, TopNav} from 'haengdong-design'; +import {StepListProvider} from '@hooks/useStepList/useStepList'; + +import HomeContent from './HomeContent'; + +const HomeLayout = () => { + return ( + <StepListProvider> + <MainLayout backgroundColor="gray"> + <TopNav navType="home" /> + <Flex flexDirection="column" gap="1rem"> + <HomeContent /> + </Flex> + </MainLayout> + </StepListProvider> + ); +}; + +export default HomeLayout; diff --git a/client/src/pages/Home/index.ts b/client/src/pages/Home/index.ts new file mode 100644 index 000000000..fde362f5c --- /dev/null +++ b/client/src/pages/Home/index.ts @@ -0,0 +1 @@ +export {default as HomePage} from './HomeLayout'; diff --git a/client/src/router.tsx b/client/src/router.tsx index b6883623b..a84ea18e5 100644 --- a/client/src/router.tsx +++ b/client/src/router.tsx @@ -3,6 +3,7 @@ import {createBrowserRouter} from 'react-router-dom'; import {MainPage} from '@pages/Main'; import {CreateNamePage, CreateCompletePage} from '@pages/Create'; import {EventPage} from '@pages/Event'; +import {HomePage} from '@pages/Home'; import {ROUTER_URLS} from '@constants/routerUrls'; @@ -30,6 +31,10 @@ const router = createBrowserRouter([ path: ROUTER_URLS.eventManage, element: <EventPage />, }, + { + path: ROUTER_URLS.home, + element: <HomePage />, + }, ], }, ]); diff --git a/client/src/types/stepList.ts b/client/src/types/stepList.ts new file mode 100644 index 000000000..f106306e9 --- /dev/null +++ b/client/src/types/stepList.ts @@ -0,0 +1,52 @@ +export type MemberType = 'IN' | 'OUT'; + +// TODO: (@weadie) 준 데이터 형식에서 steps를 빼내 flat하게 사용중. 일관성있게 하는게 좋긴 하나 사용시 번거로움이 있을 거라고 판단. +export type StepList = (MemberStep | BillStep)[]; + +export type Step = { + type: MemberType | 'BILL'; + stepName: string | null; + actions: (BillAction | MemberAction)[]; +}; + +export type MemberStep = Omit<Step, 'type' | 'stepName' | 'actions'> & { + type: MemberType; + stepName: null; + actions: MemberAction[]; +}; + +export type BillStep = Omit<Step, 'type' | 'stepName' | 'actions'> & { + type: 'BILL'; + stepName: string; + actions: BillAction[]; +}; + +export type Action = { + actionId: number; + name: string; + price: number | null; + sequence?: number; +}; + +export type BillAction = Omit<Action, 'price'> & { + price: number; +}; + +export type MemberAction = Omit<Action, 'price'> & { + price: null; +}; + +export type Member = { + name: string; + status: MemberType; +}; + +export type Bill = { + title: string; + price: number; +}; + +export type MemberReport = { + name: string; + price: number; +}; diff --git a/client/webpack.config.js b/client/webpack.config.js index b729f1020..9545ecf2f 100644 --- a/client/webpack.config.js +++ b/client/webpack.config.js @@ -8,6 +8,8 @@ import Dotenv from 'dotenv-webpack'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); +// dotenv.config({path: path.join(__dirname, '.env')}); + export default { mode: 'development', entry: './src/index.tsx', From fc4138c3a43987ea1a525979e3026c7035e74cb0 Mon Sep 17 00:00:00 2001 From: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> Date: Wed, 24 Jul 2024 14:01:23 +0900 Subject: [PATCH 075/178] =?UTF-8?q?feat:=20=ED=98=84=EC=9E=AC=20=EC=B0=B8?= =?UTF-8?q?=EC=97=AC=EC=9E=90=20=EA=B2=80=EC=83=89=20component=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20(#78)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * design: Title Component width 100%로 수정 * design: TopNav width 100%로 수정 * fix: index.tsx export 수정 * chore: v0.1.2 배포 * design: input 좌우 1rem 추가 * feat: MainLayout 추가 * chore: v0.1.3 배포 * feat: search 컴포넌트 구현 * design: input 컴포넌트 마진 추가로 searchTerms 마진 추가 * refactor: 사용하지 않는 onChange 제거 * refactor: setKeyword -> setState로 setter라는 의미 명시 * style: early return 뒤 개행 추가 --------- Co-authored-by: 이태훈 <rhymint@gmail.com> --- HDesign/package-lock.json | 4 +- HDesign/package.json | 2 +- HDesign/src/components/Input/Input.style.ts | 2 +- .../src/components/Search/Search.stories.tsx | 34 +++++++++++++++ HDesign/src/components/Search/Search.style.ts | 39 +++++++++++++++++ HDesign/src/components/Search/Search.tsx | 42 +++++++++++++++++++ HDesign/src/components/Search/useSearch.ts | 39 +++++++++++++++++ HDesign/src/components/Title/Title.style.ts | 1 + HDesign/src/components/TopNav/TopNav.style.ts | 1 + HDesign/src/index.tsx | 19 +++++++++ HDesign/src/layouts/MainLayout.tsx | 12 ++++++ HDesign/tsconfig.json | 1 + 12 files changed, 192 insertions(+), 4 deletions(-) create mode 100644 HDesign/src/components/Search/Search.stories.tsx create mode 100644 HDesign/src/components/Search/Search.style.ts create mode 100644 HDesign/src/components/Search/Search.tsx create mode 100644 HDesign/src/components/Search/useSearch.ts create mode 100644 HDesign/src/layouts/MainLayout.tsx diff --git a/HDesign/package-lock.json b/HDesign/package-lock.json index 905b380c5..9a18cd5ff 100644 --- a/HDesign/package-lock.json +++ b/HDesign/package-lock.json @@ -1,12 +1,12 @@ { "name": "haengdong-design", - "version": "0.1.0", + "version": "0.1.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "haengdong-design", - "version": "0.1.0", + "version": "0.1.3", "license": "ISC", "dependencies": { "@emotion/react": "^11.11.4", diff --git a/HDesign/package.json b/HDesign/package.json index c7dbfca71..42f857a3e 100644 --- a/HDesign/package.json +++ b/HDesign/package.json @@ -1,6 +1,6 @@ { "name": "haengdong-design", - "version": "0.1.0", + "version": "0.1.3", "description": "", "main": "./dist/index.js", "module": "./dist/index.js", diff --git a/HDesign/src/components/Input/Input.style.ts b/HDesign/src/components/Input/Input.style.ts index f45b02ea2..be05abb5b 100644 --- a/HDesign/src/components/Input/Input.style.ts +++ b/HDesign/src/components/Input/Input.style.ts @@ -19,8 +19,8 @@ const inputBoxBackgroundColorByInputType = (theme: Theme, inputType: InputType = export const inputBoxStyle = (theme: Theme, inputType: InputType = 'input') => css({ display: 'flex', - width: '100%', justifyContent: 'space-between', + marginInline: '1rem', padding: '0.75rem 1rem', borderRadius: '1rem', backgroundColor: inputBoxBackgroundColorByInputType(theme, inputType), diff --git a/HDesign/src/components/Search/Search.stories.tsx b/HDesign/src/components/Search/Search.stories.tsx new file mode 100644 index 000000000..40f7df4b1 --- /dev/null +++ b/HDesign/src/components/Search/Search.stories.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import type {Meta, StoryObj} from '@storybook/react'; + +import Search from '@components/Search/Search'; + +const meta = { + title: 'Components/Search', + component: Search, + tags: ['autodocs'], + parameters: { + // layout: 'centered', + }, + argTypes: { + value: { + description: '', + control: {type: 'text'}, + }, + inputType: { + control: {type: 'radio'}, + }, + }, + args: { + disabled: false, + placeholder: 'placeholder', + searchTerms: ['todari', 'cookie'], + setKeyword: keyword => console.log(keyword), + }, +} satisfies Meta<typeof Search>; + +export default meta; + +type Story = StoryObj<typeof meta>; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/Search/Search.style.ts b/HDesign/src/components/Search/Search.style.ts new file mode 100644 index 000000000..413655bd5 --- /dev/null +++ b/HDesign/src/components/Search/Search.style.ts @@ -0,0 +1,39 @@ +import {Theme} from '@/theme/theme.type'; +import {css} from '@emotion/react'; + +export const searchStyle = css({ + position: 'relative', + + width: '100%', +}); + +export const searchTermsStyle = (theme: Theme) => + css({ + position: 'absolute', + top: '3.5rem', + + width: 'calc(100% - 2rem)', + margin: '0 1rem', + padding: '0.5rem 0', + + borderRadius: '1rem', + + backgroundColor: theme.colors.white, + }); + +export const searchTermStyle = (theme: Theme) => + css( + { + width: '100%', + padding: '0.5rem 1rem', + + color: theme.colors.onTertiary, + + '&:hover': { + borderRadius: '0.5rem', + + backgroundColor: theme.colors.lightGrayContainer, + }, + }, + theme.typography.body, + ); diff --git a/HDesign/src/components/Search/Search.tsx b/HDesign/src/components/Search/Search.tsx new file mode 100644 index 000000000..68fc02209 --- /dev/null +++ b/HDesign/src/components/Search/Search.tsx @@ -0,0 +1,42 @@ +/** @jsxImportSource @emotion/react */ +import Input from '../Input/Input'; +import {InputProps} from '../Input/Input.type'; +import {searchStyle, searchTermsStyle} from './Search.style'; +import useSearch from './useSearch'; +import {searchTermStyle} from './Search.style'; +import {useTheme} from '@theme/HDesignProvider'; +import Flex from '@components/Flex/Flex'; + +export interface SearchProps extends InputProps { + searchTerms: string[]; + setState: React.Dispatch<React.SetStateAction<string>>; +} + +const Search: React.FC<SearchProps> = ({searchTerms, setState, ...inputProps}: SearchProps) => { + const {theme} = useTheme(); + const {value, showSearchTerms, handleOnChange, handleOnClick, filterSearchTerms} = useSearch({ + searchTerms, + setState, + }); + + return ( + <fieldset css={searchStyle}> + <Input inputType="search" value={value} onChange={handleOnChange} {...inputProps} /> + {showSearchTerms && ( + <ul css={searchTermsStyle(theme)}> + <Flex flexDirection="column" gap="0.5rem"> + {filterSearchTerms(value).map((searchTerm, index) => ( + <li key={`${searchTerm}-${index}`}> + <button type="button" css={searchTermStyle(theme)} onClick={() => handleOnClick(searchTerm)}> + {searchTerm} + </button> + </li> + ))} + </Flex> + </ul> + )} + </fieldset> + ); +}; + +export default Search; diff --git a/HDesign/src/components/Search/useSearch.ts b/HDesign/src/components/Search/useSearch.ts new file mode 100644 index 000000000..fbb9cf4c3 --- /dev/null +++ b/HDesign/src/components/Search/useSearch.ts @@ -0,0 +1,39 @@ +import {useState} from 'react'; + +interface UseSearchProps { + searchTerms: string[]; + setState: React.Dispatch<React.SetStateAction<string>>; +} + +const useSearch = ({searchTerms, setState}: UseSearchProps) => { + const [value, setValue] = useState(''); + const [showSearchTerms, setShowSearchTerms] = useState(false); + + const handleOnClick = (searchTerm: string) => { + setValue(searchTerm); + setState(searchTerm); + setShowSearchTerms(false); + }; + + const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>) => { + const {value} = event.target; + setValue(value); + setShowSearchTerms(value.trim() !== '' && filterSearchTerms(value).length !== 0); + }; + + const filterSearchTerms = (keyword: string) => { + if (keyword.trim() === '') return []; + + return searchTerms.filter(terms => terms.toLocaleLowerCase().indexOf(keyword.toLocaleLowerCase()) > -1); + }; + + return { + value, + showSearchTerms, + handleOnClick, + handleOnChange, + filterSearchTerms, + }; +}; + +export default useSearch; diff --git a/HDesign/src/components/Title/Title.style.ts b/HDesign/src/components/Title/Title.style.ts index ca0a02fc3..700128c02 100644 --- a/HDesign/src/components/Title/Title.style.ts +++ b/HDesign/src/components/Title/Title.style.ts @@ -6,6 +6,7 @@ export const titleContainerStyle = (theme: Theme) => css({ display: 'flex', flexDirection: 'column', + width: '100%', gap: '0.5rem', backgroundColor: theme.colors.white, padding: '1rem', diff --git a/HDesign/src/components/TopNav/TopNav.style.ts b/HDesign/src/components/TopNav/TopNav.style.ts index cd4244eb3..88910da47 100644 --- a/HDesign/src/components/TopNav/TopNav.style.ts +++ b/HDesign/src/components/TopNav/TopNav.style.ts @@ -3,4 +3,5 @@ import {css} from '@emotion/react'; export const topNavStyle = css({ display: 'flex', padding: '0 1rem', + width: '100%', }); diff --git a/HDesign/src/index.tsx b/HDesign/src/index.tsx index 8c010bca0..7f941ad5f 100644 --- a/HDesign/src/index.tsx +++ b/HDesign/src/index.tsx @@ -1,13 +1,23 @@ import BillItem from '@components/BillItem/BillItem'; import BottomSheet from '@components/BottomSheet/BottomSheet'; import Button from '@components/Button/Button'; +import DragHandleItem from '@components/DragHandleItem/DragHandleItem'; +import ExpenseList from '@components/ExpenseList/ExpenseList'; import FixedButton from '@components/FixedButton/FixedButton'; +import Flex from '@components/Flex/Flex'; import IconButton from '@components/IconButton/IconButton'; import InOutItem from '@components/InOutItem/InOutItem'; import Input from '@components/Input/Input'; +import Search from '@components/Search/Search'; import StepItem from '@components/StepItem/StepItem'; +import Switch from '@components/Switch/Switch'; +import Tab from '@components/Tab/Tab'; import Text from '@components/Text/Text'; +import TextButton from '@components/TextButton/TextButton'; import Title from '@components/Title/Title'; +import TopNav from '@components/TopNav/TopNav'; + +import {MainLayout} from '@layouts/MainLayout'; import {HDesignProvider} from '@theme/HDesignProvider'; @@ -15,12 +25,21 @@ export { BillItem, BottomSheet, Button, + DragHandleItem, + ExpenseList, FixedButton, + Flex, IconButton, InOutItem, Input, + Search, StepItem, + Switch, + Tab, Text, + TextButton, Title, + TopNav, + MainLayout, HDesignProvider, }; diff --git a/HDesign/src/layouts/MainLayout.tsx b/HDesign/src/layouts/MainLayout.tsx new file mode 100644 index 000000000..825aca175 --- /dev/null +++ b/HDesign/src/layouts/MainLayout.tsx @@ -0,0 +1,12 @@ +import {PropsWithChildren} from 'react'; +import {Flex} from '..'; + +interface MainLayoutInterface extends PropsWithChildren {} + +export const MainLayout = ({children}: MainLayoutInterface) => { + return ( + <Flex justifyContent="flexStart" flexDirection="column" margin="1rem 0 0 0" gap="1rem" width="100%" height="100%"> + {children} + </Flex> + ); +}; diff --git a/HDesign/tsconfig.json b/HDesign/tsconfig.json index 6cbcf91bd..371b40efe 100644 --- a/HDesign/tsconfig.json +++ b/HDesign/tsconfig.json @@ -18,6 +18,7 @@ "paths": { "@/*": ["src/*"], "@components/*": ["src/components/*"], + "@layouts/*": ["src/layouts/*"], "@token/*": ["src/token/*"], "@theme/*": ["src/theme/*"], "@assets/*": ["src/assets/*"] From 20519e755a4d63db2c00b2780a0ecea751196e4c Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Wed, 24 Jul 2024 14:04:41 +0900 Subject: [PATCH 076/178] =?UTF-8?q?feat:=20CORS=20=EC=84=A4=EC=A0=95=20(#9?= =?UTF-8?q?0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: CORS 설정 * refactor: CORS 설정 분리 * test: yml에 CORS 설정 추가 * feat: Origin 추가 * feat: Cors 설정에 HTTP OPTIONS 메서드 추가 --------- Co-authored-by: juha <khabh@naver.com> --- .../server/haengdong/config/WebConfig.java | 27 +++++++++++++++++++ server/src/main/resources/application.yml | 4 +++ server/src/test/resources/application.yml | 3 +++ 3 files changed, 34 insertions(+) create mode 100644 server/src/main/java/server/haengdong/config/WebConfig.java diff --git a/server/src/main/java/server/haengdong/config/WebConfig.java b/server/src/main/java/server/haengdong/config/WebConfig.java new file mode 100644 index 000000000..129d8b790 --- /dev/null +++ b/server/src/main/java/server/haengdong/config/WebConfig.java @@ -0,0 +1,27 @@ +package server.haengdong.config; + +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@RequiredArgsConstructor +@Configuration +public class WebConfig implements WebMvcConfigurer { + + @Value("${cors.max-age}") + private Long maxAge; + + @Value("${cors.allowed-origins}") + private String[] allowedOrigins; + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOrigins(allowedOrigins) + .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS") + .allowedHeaders("*") + .maxAge(maxAge); + } +} diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index aca841de8..e1bdd7f79 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -14,6 +14,10 @@ spring: format_sql: true show-sql: true +cors: + max-age: 3600 + allowed-origins: http://localhost:3000, https://haengdong.pro, https://dev.haengdong.pro, https://app.haengdong.pro + --- spring: diff --git a/server/src/test/resources/application.yml b/server/src/test/resources/application.yml index 49c481eaa..2d02b2712 100644 --- a/server/src/test/resources/application.yml +++ b/server/src/test/resources/application.yml @@ -13,3 +13,6 @@ spring: format_sql: true hibernate: ddl-auto: create-drop +cors: + max-age: 3600 + allowed-origins: http://localhost:8080 From cf90b45a68c3167b68e3031363a345c01680db54 Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Wed, 24 Jul 2024 14:06:13 +0900 Subject: [PATCH 077/178] =?UTF-8?q?feat:=20=ED=96=89=EC=82=AC=20=EC=BB=A4?= =?UTF-8?q?=EC=8A=A4=ED=85=80=20=EC=98=88=EC=99=B8=20=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?(#92)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 행사 커스텀 예외 처리 * feat: 커스텀 예외 적용 --- ...ication.java => HaengdongApplication.java} | 4 +- .../application/BillActionService.java | 4 +- .../haengdong/application/EventService.java | 5 ++- .../application/MemberActionFactory.java | 6 ++- .../haengdong/exception/ErrorResponse.java | 10 +++++ .../exception/GlobalExceptionHandler.java | 43 +++++++++++++++++++ .../exception/HaengdongErrorCode.java | 24 +++++++++++ .../exception/HaengdongException.java | 32 ++++++++++++++ .../application/BillActionServiceTest.java | 4 +- .../application/MemberActionFactoryTest.java | 13 +++--- 10 files changed, 131 insertions(+), 14 deletions(-) rename server/src/main/java/server/haengdong/{ServerApplication.java => HaengdongApplication.java} (69%) create mode 100644 server/src/main/java/server/haengdong/exception/ErrorResponse.java create mode 100644 server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java create mode 100644 server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java create mode 100644 server/src/main/java/server/haengdong/exception/HaengdongException.java diff --git a/server/src/main/java/server/haengdong/ServerApplication.java b/server/src/main/java/server/haengdong/HaengdongApplication.java similarity index 69% rename from server/src/main/java/server/haengdong/ServerApplication.java rename to server/src/main/java/server/haengdong/HaengdongApplication.java index 784978356..31b6e46e7 100644 --- a/server/src/main/java/server/haengdong/ServerApplication.java +++ b/server/src/main/java/server/haengdong/HaengdongApplication.java @@ -4,10 +4,10 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication -public class ServerApplication { +public class HaengdongApplication { public static void main(String[] args) { - SpringApplication.run(ServerApplication.class, args); + SpringApplication.run(HaengdongApplication.class, args); } } diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java index 272eee7e8..257d33a3e 100644 --- a/server/src/main/java/server/haengdong/application/BillActionService.java +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -11,6 +11,8 @@ import server.haengdong.domain.action.ActionRepository; import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; @RequiredArgsConstructor @Transactional(readOnly = true) @@ -24,7 +26,7 @@ public class BillActionService { @Transactional public void saveAllBillAction(String eventToken, List<BillActionAppRequest> requests) { Event event = eventRepository.findByToken(eventToken) - .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 이벤트 토큰입니다.")); + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); Action action = createStartAction(event); for (BillActionAppRequest request : requests) { diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java index ea4384148..dee023fbc 100644 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -8,6 +8,8 @@ import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.domain.event.EventTokenProvider; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; @RequiredArgsConstructor @Service @@ -25,7 +27,8 @@ public EventAppResponse saveEvent(EventAppRequest request) { } public EventDetailAppResponse findEvent(String token) { - Event event = eventRepository.findByToken(token).orElseThrow(() -> new IllegalArgumentException("")); + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); return EventDetailAppResponse.of(event); } diff --git a/server/src/main/java/server/haengdong/application/MemberActionFactory.java b/server/src/main/java/server/haengdong/application/MemberActionFactory.java index 46fd9ed1a..cbe34f0ef 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionFactory.java +++ b/server/src/main/java/server/haengdong/application/MemberActionFactory.java @@ -11,6 +11,8 @@ import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionStatus; import server.haengdong.domain.action.MemberGroupIdProvider; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; @RequiredArgsConstructor @Component @@ -45,7 +47,7 @@ private void validateMemberNames(MemberActionsSaveAppRequest request) { long uniqueCount = memberNames.stream().distinct().count(); if (uniqueCount != memberNames.size()) { - throw new IllegalArgumentException(); + throw new HaengdongException(HaengdongErrorCode.DUPLICATED_MEMBER_ACTION); } } @@ -62,7 +64,7 @@ private void validateActions(MemberActionsSaveAppRequest request, List<MemberAct private void validateAction(MemberActionSaveAppRequest request, List<MemberAction> memberActions) { MemberActionStatus memberActionStatus = MemberActionStatus.of(request.status()); if (isInvalidStatus(memberActions, request.name(), memberActionStatus)) { - throw new IllegalArgumentException(); + throw new HaengdongException(HaengdongErrorCode.INVALID_MEMBER_ACTION); } } diff --git a/server/src/main/java/server/haengdong/exception/ErrorResponse.java b/server/src/main/java/server/haengdong/exception/ErrorResponse.java new file mode 100644 index 000000000..5d1e33c9b --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/ErrorResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.exception; + +public record ErrorResponse( + String message +) { + + public static ErrorResponse of(HaengdongErrorCode errorCode) { + return new ErrorResponse(errorCode.getMessage()); + } +} diff --git a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java new file mode 100644 index 000000000..7985721cd --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java @@ -0,0 +1,43 @@ +package server.haengdong.exception; + +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@Slf4j +@RestControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + public ResponseEntity<ErrorResponse> haengdongException() { + return ResponseEntity.badRequest() + .body(ErrorResponse.of(HaengdongErrorCode.BAD_REQUEST)); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity<ErrorResponse> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { + String errorMessage = e.getFieldErrors().stream() + .map(error -> error.getField() + " " + error.getDefaultMessage()) + .collect(Collectors.joining(", ")); + + return ResponseEntity.badRequest() + .body(new ErrorResponse(errorMessage)); + } + + @ExceptionHandler(HaengdongException.class) + public ResponseEntity<ErrorResponse> haengdongException(HaengdongException e) { + return ResponseEntity.status(e.getStatusCode()) + .body(ErrorResponse.of(e.getErrorCode())); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity<ErrorResponse> handleException(Exception e) { + log.error(e.getMessage(), e); + return ResponseEntity.internalServerError() + .body(ErrorResponse.of(HaengdongErrorCode.INTERNAL_SERVER_ERROR)); + } +} diff --git a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java new file mode 100644 index 000000000..792baa838 --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java @@ -0,0 +1,24 @@ +package server.haengdong.exception; + +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +public enum HaengdongErrorCode { + BAD_REQUEST(HttpStatus.BAD_REQUEST, "잘못된 요청입니다."), + DUPLICATED_MEMBER_ACTION(HttpStatus.BAD_REQUEST, "올바르지 않은 인원 요청입니다."), + INVALID_MEMBER_ACTION(HttpStatus.BAD_REQUEST, "잘못된 맴버 액션입니다."), + + NOT_FOUND_EVENT(HttpStatus.NOT_FOUND, "존재하지 않는 행사입니다."), + + INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버 내부에서 에러가 발생했습니다."), + ; + + private final HttpStatus httpStatus; + private final String message; + + HaengdongErrorCode(HttpStatus httpStatus, String message) { + this.httpStatus = httpStatus; + this.message = message; + } +} diff --git a/server/src/main/java/server/haengdong/exception/HaengdongException.java b/server/src/main/java/server/haengdong/exception/HaengdongException.java new file mode 100644 index 000000000..812df50f8 --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/HaengdongException.java @@ -0,0 +1,32 @@ +package server.haengdong.exception; + +import lombok.Getter; +import org.springframework.http.HttpStatusCode; + +@Getter +public class HaengdongException extends RuntimeException { + + private final HaengdongErrorCode errorCode; + private final String message; + + public HaengdongException(HaengdongErrorCode errorCode) { + this(errorCode, null); + } + + public HaengdongException(HaengdongErrorCode errorCode, String message) { + this.errorCode = errorCode; + this.message = message; + } + + public HttpStatusCode getStatusCode() { + return errorCode.getHttpStatus(); + } + + @Override + public String getMessage() { + if (message == null) { + return errorCode.getMessage(); + } + return message; + } +} diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java index 178e850e3..195d4bdd9 100644 --- a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java @@ -14,6 +14,7 @@ import server.haengdong.domain.event.Event; import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongException; @SpringBootTest class BillActionServiceTest { @@ -59,7 +60,6 @@ void saveAllBillAction1() { ); assertThatThrownBy(() -> billActionService.saveAllBillAction("token", requests)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("존재하지 않는 이벤트 토큰입니다."); + .isInstanceOf(HaengdongException.class); } } diff --git a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java index b8251a307..40bee2ff6 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java @@ -20,6 +20,7 @@ import server.haengdong.domain.action.ActionRepository; import server.haengdong.domain.event.EventRepository; import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.exception.HaengdongException; @SpringBootTest class MemberActionFactoryTest { @@ -59,7 +60,7 @@ void createMemberActionsTest() { Action startAction = new Action(event, 3L); assertThatThrownBy(() -> memberActionFactory.createMemberActions(request, unorderedMemberActions, startAction)) - .isInstanceOf(IllegalArgumentException.class); + .isInstanceOf(HaengdongException.class); } @DisplayName("인원 변동 액션을 생성한다.") @@ -147,7 +148,7 @@ void createMemberActionTest5() { Action startAction = new Action(event, 2L); assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(), startAction)) - .isInstanceOf(IllegalArgumentException.class); + .isInstanceOf(HaengdongException.class); } @DisplayName("행사에 이미 참여 중인 경우 다시 입장할 수 없다.") @@ -163,7 +164,7 @@ void createMemberActionTest6() { Action startAction = new Action(event, 2L); assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) - .isInstanceOf(IllegalArgumentException.class); + .isInstanceOf(HaengdongException.class); } @DisplayName("한 명의 사용자는 동시에 여러 번 입장할 수 없다.") @@ -177,7 +178,7 @@ void createMemberActionTest7() { Action startAction = new Action(event, 1L); assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(), startAction)) - .isInstanceOf(IllegalArgumentException.class); + .isInstanceOf(HaengdongException.class); } @DisplayName("한 명의 사용자는 동시에 여러 번 퇴장할 수 없다.") @@ -194,7 +195,7 @@ void createMemberActionTest8() { Action startAction = new Action(event, 2L); assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) - .isInstanceOf(IllegalArgumentException.class); + .isInstanceOf(HaengdongException.class); } @DisplayName("한 명의 사용자는 입장과 퇴장을 동시에 할 수 없다.") @@ -211,6 +212,6 @@ void createMemberActionTest9() { Action startAction = new Action(event, 2L); assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) - .isInstanceOf(IllegalArgumentException.class); + .isInstanceOf(HaengdongException.class); } } From a6e9ea2ef4e1a59a97c318d078530771a6f538c7 Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Wed, 24 Jul 2024 15:26:27 +0900 Subject: [PATCH 078/178] =?UTF-8?q?feat:=20=EC=B0=B8=EC=97=AC=EC=9E=90?= =?UTF-8?q?=EB=B3=84=20=EC=A0=95=EC=82=B0=20=ED=98=84=ED=99=A9=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20(#77)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../haengdong/application/ActionService.java | 38 +++++++++ .../response/MemberBillReportAppResponse.java | 4 + .../haengdong/domain/action/BillAction.java | 7 +- .../haengdong/domain/action/MemberAction.java | 7 +- .../domain/action/MemberBillReports.java | 83 +++++++++++++++++++ .../presentation/ActionController.java | 26 ++++++ .../response/MemberBillReportResponse.java | 10 +++ .../response/MemberBillReportsResponse.java | 15 ++++ .../application/ActionServiceTest.java | 68 +++++++++++++++ .../domain/action/MemberBillReportsTest.java | 43 ++++++++++ .../presentation/ActionControllerTest.java | 49 +++++++++++ 11 files changed, 348 insertions(+), 2 deletions(-) create mode 100644 server/src/main/java/server/haengdong/application/ActionService.java create mode 100644 server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java create mode 100644 server/src/main/java/server/haengdong/domain/action/MemberBillReports.java create mode 100644 server/src/main/java/server/haengdong/presentation/ActionController.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java create mode 100644 server/src/test/java/server/haengdong/application/ActionServiceTest.java create mode 100644 server/src/test/java/server/haengdong/domain/action/MemberBillReportsTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/ActionControllerTest.java diff --git a/server/src/main/java/server/haengdong/application/ActionService.java b/server/src/main/java/server/haengdong/application/ActionService.java new file mode 100644 index 000000000..22ca43a6b --- /dev/null +++ b/server/src/main/java/server/haengdong/application/ActionService.java @@ -0,0 +1,38 @@ +package server.haengdong.application; + +import java.util.ArrayList; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import server.haengdong.application.response.MemberBillReportAppResponse; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.action.MemberBillReports; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; + +@RequiredArgsConstructor +@Service +public class ActionService { + + private final BillActionRepository billActionRepository; + private final MemberActionRepository memberActionRepository; + private final EventRepository eventRepository; + + public List<MemberBillReportAppResponse> getMemberBillReports(String token) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new IllegalArgumentException("event not found")); + List<BillAction> billActions = billActionRepository.findByAction_Event(event); + List<MemberAction> memberActions = memberActionRepository.findAllByEvent(event); + + MemberBillReports memberBillReports = MemberBillReports.createByActions(billActions, memberActions); + + List<MemberBillReportAppResponse> memberBillReportResponses = new ArrayList<>(); + memberBillReports.getReports().forEach( + (member, price) -> memberBillReportResponses.add(new MemberBillReportAppResponse(member, price)) + ); + return memberBillReportResponses; + } +} diff --git a/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java b/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java new file mode 100644 index 000000000..21b6cef56 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java @@ -0,0 +1,4 @@ +package server.haengdong.application.response; + +public record MemberBillReportAppResponse(String name, Long price) { +} diff --git a/server/src/main/java/server/haengdong/domain/action/BillAction.java b/server/src/main/java/server/haengdong/domain/action/BillAction.java index 503715fa1..f0e82c409 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillAction.java +++ b/server/src/main/java/server/haengdong/domain/action/BillAction.java @@ -15,7 +15,7 @@ @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Entity -public class BillAction { +public class BillAction implements Comparable<BillAction> { private static final int MIN_TITLE_LENGTH = 2; private static final int MAX_TITLE_LENGTH = 30; @@ -58,4 +58,9 @@ private void validatePrice(Long price) { public Long getSequence() { return action.getSequence(); } + + @Override + public int compareTo(BillAction o) { + return Long.compare(this.getSequence(), o.getSequence()); + } } diff --git a/server/src/main/java/server/haengdong/domain/action/MemberAction.java b/server/src/main/java/server/haengdong/domain/action/MemberAction.java index 6e5f0d805..af340de3f 100644 --- a/server/src/main/java/server/haengdong/domain/action/MemberAction.java +++ b/server/src/main/java/server/haengdong/domain/action/MemberAction.java @@ -16,7 +16,7 @@ @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Entity -public class MemberAction { +public class MemberAction implements Comparable<MemberAction> { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -50,4 +50,9 @@ public boolean isSameStatus(MemberActionStatus memberActionStatus) { public Long getSequence() { return action.getSequence(); } + + @Override + public int compareTo(MemberAction o) { + return Long.compare(this.getSequence(), o.getSequence()); + } } diff --git a/server/src/main/java/server/haengdong/domain/action/MemberBillReports.java b/server/src/main/java/server/haengdong/domain/action/MemberBillReports.java new file mode 100644 index 000000000..aa928d2e4 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/MemberBillReports.java @@ -0,0 +1,83 @@ +package server.haengdong.domain.action; + +import static java.util.stream.Collectors.toMap; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.PriorityQueue; +import java.util.Set; +import java.util.function.Function; +import lombok.Getter; + +@Getter +public class MemberBillReports { + + private final Map<String, Long> reports; + + private MemberBillReports(Map<String, Long> reports) { + this.reports = reports; + } + + public static MemberBillReports createByActions(List<BillAction> billActions, List<MemberAction> memberActions) { + PriorityQueue<BillAction> sortedBillActions = new PriorityQueue<>(billActions); + PriorityQueue<MemberAction> sortedMemberActions = new PriorityQueue<>(memberActions); + + Map<String, Long> memberBillReports = initReports(memberActions); + Set<String> currentMembers = new HashSet<>(); + + while (!sortedBillActions.isEmpty() && !sortedMemberActions.isEmpty()) { + if (isMemberActionTurn(sortedMemberActions, sortedBillActions)) { + addMemberAction(sortedMemberActions, currentMembers); + continue; + } + addBillAction(sortedBillActions, currentMembers, memberBillReports); + } + + while (!sortedBillActions.isEmpty()) { + addBillAction(sortedBillActions, currentMembers, memberBillReports); + } + + return new MemberBillReports(memberBillReports); + } + + private static Map<String, Long> initReports(List<MemberAction> memberActions) { + return memberActions.stream() + .map(MemberAction::getMemberName) + .distinct() + .collect(toMap(Function.identity(), i -> 0L)); + } + + private static boolean isMemberActionTurn( + PriorityQueue<MemberAction> memberActions, + PriorityQueue<BillAction> billActions + ) { + MemberAction memberAction = memberActions.peek(); + BillAction billAction = billActions.peek(); + + return memberAction.getSequence() < billAction.getSequence(); + } + + private static void addMemberAction(PriorityQueue<MemberAction> sortedMemberActions, Set<String> currentMembers) { + MemberAction memberAction = sortedMemberActions.poll(); + String memberName = memberAction.getMemberName(); + if (memberAction.isSameStatus(MemberActionStatus.IN)) { + currentMembers.add(memberName); + return; + } + currentMembers.remove(memberAction.getMemberName()); + } + + private static void addBillAction( + PriorityQueue<BillAction> sortedBillActions, + Set<String> currentMembers, + Map<String, Long> memberBillReports + ) { + BillAction billAction = sortedBillActions.poll(); + Long pricePerMember = billAction.getPrice() / currentMembers.size(); + for (String currentMember : currentMembers) { + Long price = memberBillReports.getOrDefault(currentMember, 0L) + pricePerMember; + memberBillReports.put(currentMember, price); + } + } +} diff --git a/server/src/main/java/server/haengdong/presentation/ActionController.java b/server/src/main/java/server/haengdong/presentation/ActionController.java new file mode 100644 index 000000000..fbde65a24 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/ActionController.java @@ -0,0 +1,26 @@ +package server.haengdong.presentation; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.ActionService; +import server.haengdong.application.response.MemberBillReportAppResponse; +import server.haengdong.presentation.response.MemberBillReportsResponse; + +@RequiredArgsConstructor +@RestController +public class ActionController { + + private final ActionService actionService; + + @GetMapping("/api/events/{token}/actions/reports") + public ResponseEntity<MemberBillReportsResponse> getMemberBillReports(@PathVariable("token") String token) { + List<MemberBillReportAppResponse> memberBillReports = actionService.getMemberBillReports(token); + + return ResponseEntity.ok() + .body(MemberBillReportsResponse.of(memberBillReports)); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java new file mode 100644 index 000000000..0ea409202 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.MemberBillReportAppResponse; + +public record MemberBillReportResponse(String name, Long price) { + + public static MemberBillReportResponse of(MemberBillReportAppResponse memberBillReportAppResponse) { + return new MemberBillReportResponse(memberBillReportAppResponse.name(), memberBillReportAppResponse.price()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java new file mode 100644 index 000000000..d350c4009 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java @@ -0,0 +1,15 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import server.haengdong.application.response.MemberBillReportAppResponse; + +public record MemberBillReportsResponse(List<MemberBillReportResponse> reports) { + + public static MemberBillReportsResponse of(List<MemberBillReportAppResponse> memberBillReports) { + List<MemberBillReportResponse> reports = memberBillReports.stream() + .map(MemberBillReportResponse::of) + .toList(); + + return new MemberBillReportsResponse(reports); + } +} diff --git a/server/src/test/java/server/haengdong/application/ActionServiceTest.java b/server/src/test/java/server/haengdong/application/ActionServiceTest.java new file mode 100644 index 000000000..3680b10d5 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/ActionServiceTest.java @@ -0,0 +1,68 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import server.haengdong.application.response.MemberBillReportAppResponse; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; + +@SpringBootTest +class ActionServiceTest { + + @Autowired + private ActionService actionService; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillActionRepository billActionRepository; + + @Autowired + private MemberActionRepository memberActionRepository; + + @DisplayName("참여자별 정산 현황을 조회한다.") + @Test + void getMemberBillReports() { + String token = "tOkEn1"; + Event event = new Event("행동대장", token); + Event savedEvent = eventRepository.save(event); + List<MemberAction> memberActions = List.of( + new MemberAction(new Action(savedEvent, 1L), "소하", IN, 1L), + new MemberAction(new Action(savedEvent, 2L), "감자", IN, 1L), + new MemberAction(new Action(savedEvent, 3L), "쿠키", IN, 1L), + new MemberAction(new Action(savedEvent, 5L), "감자", OUT, 2L) + ); + List<BillAction> billActions = List.of( + new BillAction(new Action(savedEvent, 4L), "뽕족", 60_000L), + new BillAction(new Action(savedEvent, 6L), "인생맥주", 40_000L), + new BillAction(new Action(savedEvent, 7L), "인생네컷", 20_000L) + ); + memberActionRepository.saveAll(memberActions); + billActionRepository.saveAll(billActions); + + List<MemberBillReportAppResponse> responses = actionService.getMemberBillReports(token); + + assertThat(responses) + .hasSize(3) + .extracting(MemberBillReportAppResponse::name, MemberBillReportAppResponse::price) + .containsExactlyInAnyOrder( + tuple("감자", 20_000L), + tuple("쿠키", 50_000L), + tuple("소하", 50_000L) + ); + } +} diff --git a/server/src/test/java/server/haengdong/domain/action/MemberBillReportsTest.java b/server/src/test/java/server/haengdong/domain/action/MemberBillReportsTest.java new file mode 100644 index 000000000..db0e2ff37 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/action/MemberBillReportsTest.java @@ -0,0 +1,43 @@ +package server.haengdong.domain.action; + +import static org.assertj.core.api.Assertions.assertThat; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; + +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.domain.event.Event; + +class MemberBillReportsTest { + + @DisplayName("액션 목록으로 참가자 정산 리포트를 생성한다.") + @Test + void createByActions() { + String token = "TOK2N"; + Event event = new Event("행동대장", token); + List<BillAction> billActions = List.of( + new BillAction(new Action(event, 4L), "뽕족", 60_000L), + new BillAction(new Action(event, 6L), "인생맥주", 40_000L), + new BillAction(new Action(event, 7L), "인생네컷", 20_000L) + ); + List<MemberAction> memberActions = List.of( + new MemberAction(new Action(event, 1L), "소하", IN, 1L), + new MemberAction(new Action(event, 2L), "감자", IN, 1L), + new MemberAction(new Action(event, 3L), "쿠키", IN, 1L), + new MemberAction(new Action(event, 5L), "감자", OUT, 2L) + ); + + MemberBillReports memberBillReports = MemberBillReports.createByActions(billActions, memberActions); + + assertThat(memberBillReports.getReports()) + .containsAllEntriesOf( + Map.of( + "감자", 20_000L, + "쿠키", 50_000L, + "소하", 50_000L + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java new file mode 100644 index 000000000..739ac4962 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java @@ -0,0 +1,49 @@ +package server.haengdong.presentation; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import server.haengdong.application.ActionService; +import server.haengdong.application.response.MemberBillReportAppResponse; + +@WebMvcTest(ActionController.class) +class ActionControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private ActionService actionService; + + @DisplayName("참여자별 정산 현황을 조회한다.") + @Test + void getMemberBillReports() throws Exception { + List<MemberBillReportAppResponse> memberBillReportAppResponses = List.of( + new MemberBillReportAppResponse("소하", 20_000L), new MemberBillReportAppResponse("토다리", 200_000L)); + + given(actionService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); + + mockMvc.perform(get("/api/events/{token}/actions/reports", "token") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].name").value(equalTo("소하"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].price").value(equalTo(20_000))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].name").value(equalTo("토다리"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].price").value(equalTo(200_000))); + + } +} From 8ed9900339b82cef0232ca78c6ad856539eb885f Mon Sep 17 00:00:00 2001 From: Juhwan Kim <13selfesteem91@naver.com> Date: Wed, 24 Jul 2024 19:25:11 +0900 Subject: [PATCH 079/178] =?UTF-8?q?feat:=20api=20=EB=AA=85=EC=84=B8?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=ED=96=89=EC=82=AC=20url=EC=9D=84=20?= =?UTF-8?q?=ED=91=9C=ED=98=84=ED=95=98=EB=8A=94=20=EC=9A=A9=EC=96=B4?= =?UTF-8?q?=EC=99=80=20=EC=A0=84=EB=8B=AC=20=EB=B0=A9=EC=8B=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20(#98)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 행사 url 명세를 token에서 eventId로 변경 * feat: 행사 url을 헤더가 아닌 바디로 전달 * test: 행사 생성 컨트롤러 테스트 수정 * feat: 행사 생성 응답 dto에 필드명 수정 --- .../haengdong/presentation/ActionController.java | 4 ++-- .../presentation/BillActionController.java | 4 ++-- .../haengdong/presentation/EventController.java | 15 ++++++--------- .../presentation/MemberActionController.java | 8 ++++---- .../presentation/response/EventResponse.java | 10 ++++++++++ .../presentation/EventControllerTest.java | 3 +-- 6 files changed, 25 insertions(+), 19 deletions(-) create mode 100644 server/src/main/java/server/haengdong/presentation/response/EventResponse.java diff --git a/server/src/main/java/server/haengdong/presentation/ActionController.java b/server/src/main/java/server/haengdong/presentation/ActionController.java index fbde65a24..657cb567e 100644 --- a/server/src/main/java/server/haengdong/presentation/ActionController.java +++ b/server/src/main/java/server/haengdong/presentation/ActionController.java @@ -16,8 +16,8 @@ public class ActionController { private final ActionService actionService; - @GetMapping("/api/events/{token}/actions/reports") - public ResponseEntity<MemberBillReportsResponse> getMemberBillReports(@PathVariable("token") String token) { + @GetMapping("/api/events/{eventId}/actions/reports") + public ResponseEntity<MemberBillReportsResponse> getMemberBillReports(@PathVariable("eventId") String token) { List<MemberBillReportAppResponse> memberBillReports = actionService.getMemberBillReports(token); return ResponseEntity.ok() diff --git a/server/src/main/java/server/haengdong/presentation/BillActionController.java b/server/src/main/java/server/haengdong/presentation/BillActionController.java index 139d6a470..fcdacb270 100644 --- a/server/src/main/java/server/haengdong/presentation/BillActionController.java +++ b/server/src/main/java/server/haengdong/presentation/BillActionController.java @@ -16,9 +16,9 @@ public class BillActionController { private final BillActionService billActionService; - @PostMapping("/api/events/{token}/actions/bills") + @PostMapping("/api/events/{eventId}/actions/bills") public ResponseEntity<Void> saveAllBillAction( - @PathVariable String token, + @PathVariable("eventId") String token, @RequestBody @Valid BillActionsSaveRequest request ) { billActionService.saveAllBillAction(token, request.toAppRequests()); diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java index 538ca9c1e..263bc35aa 100644 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -1,6 +1,5 @@ package server.haengdong.presentation; -import java.net.URI; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -9,9 +8,9 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import server.haengdong.application.EventService; -import server.haengdong.application.response.EventAppResponse; import server.haengdong.presentation.request.EventSaveRequest; import server.haengdong.presentation.response.EventDetailResponse; +import server.haengdong.presentation.response.EventResponse; @RequiredArgsConstructor @RestController @@ -20,16 +19,14 @@ public class EventController { private final EventService eventService; @PostMapping("/api/events") - public ResponseEntity<Void> saveEvent(@RequestBody EventSaveRequest request) { - EventAppResponse eventAppResponse = eventService.saveEvent(request.toAppRequest()); + public ResponseEntity<EventResponse> saveEvent(@RequestBody EventSaveRequest request) { + EventResponse eventResponse = EventResponse.of(eventService.saveEvent(request.toAppRequest())); - return ResponseEntity.ok() - .location(URI.create("events/" + eventAppResponse.token())) - .build(); + return ResponseEntity.ok(eventResponse); } - @GetMapping("/api/events/{token}") - public ResponseEntity<EventDetailResponse> findEvent(@PathVariable("token") String token) { + @GetMapping("/api/events/{eventId}") + public ResponseEntity<EventDetailResponse> findEvent(@PathVariable("eventId") String token) { EventDetailResponse eventDetailResponse = EventDetailResponse.of(eventService.findEvent(token)); return ResponseEntity.ok(eventDetailResponse); diff --git a/server/src/main/java/server/haengdong/presentation/MemberActionController.java b/server/src/main/java/server/haengdong/presentation/MemberActionController.java index cd45e3237..c12370d86 100644 --- a/server/src/main/java/server/haengdong/presentation/MemberActionController.java +++ b/server/src/main/java/server/haengdong/presentation/MemberActionController.java @@ -19,9 +19,9 @@ public class MemberActionController { private final MemberActionService memberActionService; - @PostMapping("/api/events/{token}/actions/members") + @PostMapping("/api/events/{eventId}/actions/members") public ResponseEntity<Void> saveMemberAction( - @PathVariable("token") String token, + @PathVariable("eventId") String token, @RequestBody MemberActionsSaveRequest request ) { memberActionService.saveMemberAction(token, request.toAppRequest()); @@ -29,8 +29,8 @@ public ResponseEntity<Void> saveMemberAction( return ResponseEntity.ok().build(); } - @GetMapping("/api/events/{token}/members/current") - public ResponseEntity<CurrentMembersResponse> getCurrentMembers(@PathVariable("token") String token) { + @GetMapping("/api/events/{eventId}/members/current") + public ResponseEntity<CurrentMembersResponse> getCurrentMembers(@PathVariable("eventId") String token) { List<CurrentMemberAppResponse> currentMembers = memberActionService.getCurrentMembers(token); return ResponseEntity.ok() diff --git a/server/src/main/java/server/haengdong/presentation/response/EventResponse.java b/server/src/main/java/server/haengdong/presentation/response/EventResponse.java new file mode 100644 index 000000000..506f5e814 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/EventResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.EventAppResponse; + +public record EventResponse(String eventId) { + + public static EventResponse of(EventAppResponse eventAppResponse) { + return new EventResponse(eventAppResponse.token()); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java index c50431696..55a48630f 100644 --- a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java @@ -16,7 +16,6 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import server.haengdong.application.EventService; import server.haengdong.application.request.EventAppRequest; import server.haengdong.application.response.EventAppResponse; @@ -49,7 +48,7 @@ void saveEvent() throws Exception { .content(requestBody)) .andDo(print()) .andExpect(status().isOk()) - .andExpect(MockMvcResultMatchers.redirectedUrl("events/" + token)); + .andExpect(jsonPath("$.eventId").value("TOKEN")); } @DisplayName("토큰으로 행사를 조회한다.") From 2eaeb4b14445141f3f425d892442e63eb2652f93 Mon Sep 17 00:00:00 2001 From: Juhwan Kim <13selfesteem91@naver.com> Date: Wed, 24 Jul 2024 23:42:10 +0900 Subject: [PATCH 080/178] =?UTF-8?q?feat:=20=EA=B8=B0=EB=B3=B8=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=8C=8C=EC=9D=BC=EC=97=90=EC=84=9C=20DB=EB=A5=BC=20M?= =?UTF-8?q?ySQL=EC=9D=84=20H2=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20(#102)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 기본 프로파일에서 DB를 MySQL을 H2로 변경 * feat: jpa dll-auto none에서 create로 변경 --- server/src/main/resources/application.yml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index e1bdd7f79..faf7a36f1 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -1,17 +1,21 @@ spring: datasource: - url: jdbc:mysql://localhost:3306/haengdong - username: root - password: 1234 - driver-class-name: com.mysql.cj.jdbc.Driver + driver-class-name: org.h2.Driver + url: jdbc:h2:mem:database + username: sa + password: + + h2: + console: + enabled: true + path: /h2-console jpa: hibernate: - ddl-auto: none + ddl-auto: create properties: hibernate: - dialect: org.hibernate.dialect.MySQL8Dialect - format_sql: true + format_sql: true show-sql: true cors: From 2248e9d95535d0b19e083b87322f28cc457cbf9c Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Thu, 25 Jul 2024 10:21:46 +0900 Subject: [PATCH 081/178] =?UTF-8?q?refactor:=20=EC=A7=80=EC=B6=9C=20?= =?UTF-8?q?=EB=82=B4=EC=97=AD=20=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=ED=98=84?= =?UTF-8?q?=EC=9E=AC=20=EC=B0=B8=EC=97=AC=20=EC=9D=B8=EC=9B=90=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=98=88=EC=99=B8=20=EB=A9=94=EC=8B=9C=EC=A7=80=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20(#100)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 지출 내역 생성 예외 메시지 변경 * refactor: 현재 인원 조회 예외 메시지 변경 * refactor: 예외 메시지 전달 방법 수정 --- .../server/haengdong/application/MemberActionService.java | 4 +++- .../java/server/haengdong/domain/action/BillAction.java | 8 ++++++-- .../presentation/request/BillActionSaveRequest.java | 7 ++----- .../haengdong/application/MemberActionServiceTest.java | 5 +++-- .../server/haengdong/domain/action/BillActionTest.java | 5 +++-- 5 files changed, 17 insertions(+), 12 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java index ba17b28c4..5094bf2c0 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionService.java +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -13,6 +13,8 @@ import server.haengdong.domain.action.MemberActionRepository; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; @RequiredArgsConstructor @Transactional(readOnly = true) @@ -53,6 +55,6 @@ public List<CurrentMemberAppResponse> getCurrentMembers(String token) { private Event findEvent(String token) { return eventRepository.findByToken(token) - .orElseThrow(() -> new IllegalArgumentException("event not found")); + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); } } diff --git a/server/src/main/java/server/haengdong/domain/action/BillAction.java b/server/src/main/java/server/haengdong/domain/action/BillAction.java index f0e82c409..1027206f5 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillAction.java +++ b/server/src/main/java/server/haengdong/domain/action/BillAction.java @@ -11,6 +11,8 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @@ -45,13 +47,15 @@ public BillAction(Action action, String title, Long price) { private void validateTitle(String title) { int titleLength = title.trim().length(); if (titleLength < MIN_TITLE_LENGTH || titleLength > MAX_TITLE_LENGTH) { - throw new IllegalArgumentException("앞뒤 공백을 제거한 지출 내역 제목은 2 ~ 30자여야 합니다."); + throw new HaengdongException(HaengdongErrorCode.BAD_REQUEST, + String.format("앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다.", MIN_TITLE_LENGTH, MAX_TITLE_LENGTH)); } } private void validatePrice(Long price) { if (price < MIN_PRICE || price > MAX_PRICE) { - throw new IllegalArgumentException("지출 금액은 10,000,000 이하의 자연수여야 합니다."); + throw new HaengdongException(HaengdongErrorCode.BAD_REQUEST, + String.format("지출 금액은 %,d 이하의 자연수여야 합니다.", MAX_PRICE)); } } diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java index 8d662050f..a0d878f7f 100644 --- a/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java @@ -1,18 +1,15 @@ package server.haengdong.presentation.request; +import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Positive; -import jakarta.validation.constraints.Size; import server.haengdong.application.request.BillActionAppRequest; public record BillActionSaveRequest( - @NotNull - @Size(min = 2, max = 30) + @NotBlank String title, @NotNull - @Positive Long price ) { diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java index 378aa6006..7212e300d 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java @@ -19,6 +19,7 @@ import server.haengdong.domain.action.MemberActionRepository; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongException; @SpringBootTest class MemberActionServiceTest { @@ -79,13 +80,13 @@ void saveMemberActionTest2() { List.of(new MemberActionSaveAppRequest("TOKEN", "OUT"))); assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", appRequest)) - .isInstanceOf(IllegalArgumentException.class); + .isInstanceOf(HaengdongException.class); } @DisplayName("이벤트가 없으면 현재 참여 인원을 조회할 수 없다.") @Test void getCurrentMembers() { assertThatThrownBy(() -> memberActionService.getCurrentMembers("token")) - .isInstanceOf(IllegalArgumentException.class); + .isInstanceOf(HaengdongException.class); } } diff --git a/server/src/test/java/server/haengdong/domain/action/BillActionTest.java b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java index d179ca6eb..601ca95d7 100644 --- a/server/src/test/java/server/haengdong/domain/action/BillActionTest.java +++ b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java @@ -9,6 +9,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import server.haengdong.domain.event.Event; +import server.haengdong.exception.HaengdongException; class BillActionTest { @@ -21,7 +22,7 @@ void validateTitle(String title) { Long price = 100L; assertThatThrownBy(() -> new BillAction(action, title, price)) - .isInstanceOf(IllegalArgumentException.class) + .isInstanceOf(HaengdongException.class) .hasMessage("앞뒤 공백을 제거한 지출 내역 제목은 2 ~ 30자여야 합니다."); } @@ -34,7 +35,7 @@ void validatePrice(long price) { String title = "title"; assertThatThrownBy(() -> new BillAction(action, title, price)) - .isInstanceOf(IllegalArgumentException.class) + .isInstanceOf(HaengdongException.class) .hasMessage("지출 금액은 10,000,000 이하의 자연수여야 합니다."); } From 2610de813b66cb699e61f2984f8f3bd28f18f64a Mon Sep 17 00:00:00 2001 From: JUHA <84626225+khabh@users.noreply.github.com> Date: Thu, 25 Jul 2024 10:22:37 +0900 Subject: [PATCH 082/178] =?UTF-8?q?refactor:=20=EC=B0=B8=EC=97=AC=EC=9E=90?= =?UTF-8?q?=EB=B3=84=20=EC=A0=95=EC=82=B0=20=ED=98=84=ED=99=A9=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=98=88=EC=99=B8=20=EB=A9=94=EC=8B=9C=EC=A7=80=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20(#106)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/haengdong/application/ActionService.java | 4 +++- .../haengdong/application/ActionServiceTest.java | 11 +++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/server/haengdong/application/ActionService.java b/server/src/main/java/server/haengdong/application/ActionService.java index 22ca43a6b..b28374bb9 100644 --- a/server/src/main/java/server/haengdong/application/ActionService.java +++ b/server/src/main/java/server/haengdong/application/ActionService.java @@ -12,6 +12,8 @@ import server.haengdong.domain.action.MemberBillReports; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; @RequiredArgsConstructor @Service @@ -23,7 +25,7 @@ public class ActionService { public List<MemberBillReportAppResponse> getMemberBillReports(String token) { Event event = eventRepository.findByToken(token) - .orElseThrow(() -> new IllegalArgumentException("event not found")); + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); List<BillAction> billActions = billActionRepository.findByAction_Event(event); List<MemberAction> memberActions = memberActionRepository.findAllByEvent(event); diff --git a/server/src/test/java/server/haengdong/application/ActionServiceTest.java b/server/src/test/java/server/haengdong/application/ActionServiceTest.java index 3680b10d5..ac2dc4f4f 100644 --- a/server/src/test/java/server/haengdong/application/ActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/ActionServiceTest.java @@ -1,6 +1,7 @@ package server.haengdong.application; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.tuple; import static server.haengdong.domain.action.MemberActionStatus.IN; import static server.haengdong.domain.action.MemberActionStatus.OUT; @@ -18,6 +19,8 @@ import server.haengdong.domain.action.MemberActionRepository; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; @SpringBootTest class ActionServiceTest { @@ -65,4 +68,12 @@ void getMemberBillReports() { tuple("소하", 50_000L) ); } + + @DisplayName("존재하지 않는 이벤트의 참여자별 정산 현황을 조회하는 경우 예외가 발생한다.") + @Test + void getMemberBillReports1() { + assertThatThrownBy(() -> actionService.getMemberBillReports("invalid token")) + .isInstanceOf(HaengdongException.class) + .hasMessage(HaengdongErrorCode.NOT_FOUND_EVENT.getMessage()); + } } From 3e2c5b07a54a6efe24081e0d20fb6e93656f0981 Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Thu, 25 Jul 2024 10:30:29 +0900 Subject: [PATCH 083/178] =?UTF-8?q?refactor:=20=ED=96=89=EC=82=AC=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20API=20=EC=98=88=EC=99=B8=20=EB=A9=94?= =?UTF-8?q?=EC=84=B8=EC=A7=80=20=EB=B0=8F=20DTO=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EC=95=A0=EB=84=88=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(#103)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 행사 생성 API 예외 메세지 추가 및 DTO 검증 애너테이션 추가 * refactor: 행사 생성 API EventSaveRequest name을 eventName으로 변경 * refactor: 행사 생성 요청 객체 검증 애너테이션 @Size 제거 * refactor: 연속된 공백 검증 및 예외 메세지 상수 사용하도록 리팩터링 --- .../server/haengdong/domain/event/Event.java | 26 +++++++++++++ .../presentation/EventController.java | 3 +- .../request/EventSaveRequest.java | 9 ++++- .../haengdong/domain/event/EventTest.java | 37 +++++++++++++++++++ 4 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 server/src/test/java/server/haengdong/domain/event/EventTest.java diff --git a/server/src/main/java/server/haengdong/domain/event/Event.java b/server/src/main/java/server/haengdong/domain/event/Event.java index c6877e1a6..24369a184 100644 --- a/server/src/main/java/server/haengdong/domain/event/Event.java +++ b/server/src/main/java/server/haengdong/domain/event/Event.java @@ -7,12 +7,18 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Entity public class Event { + private static final int MIN_NAME_LENGTH = 2; + private static final int MAX_NAME_LENGTH = 20; + private static final String SPACES = " "; + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @@ -22,7 +28,27 @@ public class Event { private String token; public Event(String name, String token) { + validateName(name); this.name = name; this.token = token; } + + private void validateName(String name) { + int nameLength = name.length(); + if (nameLength < MIN_NAME_LENGTH || MAX_NAME_LENGTH < nameLength) { + throw new HaengdongException(HaengdongErrorCode.BAD_REQUEST, + String.format("행사 이름은 %d자 이상 %d자 이하만 입력 가능합니다. 입력한 이름 길이 : %d", + MIN_NAME_LENGTH, + MAX_NAME_LENGTH, + name.length())); + } + if (isBlankContinuous(name)) { + throw new HaengdongException(HaengdongErrorCode.BAD_REQUEST, + String.format("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s", name)); + } + } + + private boolean isBlankContinuous(String name) { + return name.contains(SPACES); + } } diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java index 263bc35aa..260253e8b 100644 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -1,5 +1,6 @@ package server.haengdong.presentation; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -19,7 +20,7 @@ public class EventController { private final EventService eventService; @PostMapping("/api/events") - public ResponseEntity<EventResponse> saveEvent(@RequestBody EventSaveRequest request) { + public ResponseEntity<EventResponse> saveEvent(@Valid @RequestBody EventSaveRequest request) { EventResponse eventResponse = EventResponse.of(eventService.saveEvent(request.toAppRequest())); return ResponseEntity.ok(eventResponse); diff --git a/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java index 8bd4cfda8..b28572332 100644 --- a/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java @@ -1,10 +1,15 @@ package server.haengdong.presentation.request; +import jakarta.validation.constraints.NotBlank; import server.haengdong.application.request.EventAppRequest; -public record EventSaveRequest(String name) { +public record EventSaveRequest( + + @NotBlank + String eventName +) { public EventAppRequest toAppRequest() { - return new EventAppRequest(name); + return new EventAppRequest(eventName); } } diff --git a/server/src/test/java/server/haengdong/domain/event/EventTest.java b/server/src/test/java/server/haengdong/domain/event/EventTest.java new file mode 100644 index 000000000..98f6c7050 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/event/EventTest.java @@ -0,0 +1,37 @@ +package server.haengdong.domain.event; + +import static org.assertj.core.api.Assertions.assertThatCode; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import server.haengdong.exception.HaengdongException; + +class EventTest { + + @DisplayName("공백 문자가 연속되지 않고, 이름이 2자 이상 20자 이하인 행사를 생성하면 예외가 발생하지 않는다.") + @ParameterizedTest + @ValueSource(strings = {"12", "12345678901234567890", "공 백", " 공백", "공백 ", " 공 백 "}) + void createSuccessTest(String eventName) { + assertThatCode(() -> new Event(eventName, "TEST_TOKEN")) + .doesNotThrowAnyException(); + } + + @DisplayName("공백 문자가 연속되면 예외가 발생한다.") + @ParameterizedTest + @ValueSource(strings = {" 공백", "공백 ", "공백 연속", "공 백"}) + void createFailTest1(String eventName) { + assertThatCode(() -> new Event(eventName, "TEST_TOKEN")) + .isInstanceOf(HaengdongException.class) + .hasMessage(String.format("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s", eventName)); + } + + @DisplayName("이름이 2자 미만이거나 20자 초과인 경우 예외가 발생한다.") + @ParameterizedTest + @ValueSource(strings = {"", " ", "123456789012345678901"}) + void createFilTest2(String eventName) { + assertThatCode(() -> new Event(eventName, "TEST_TOKEN")) + .isInstanceOf(HaengdongException.class) + .hasMessage(String.format("행사 이름은 2자 이상 20자 이하만 입력 가능합니다. 입력한 이름 길이 : %d", eventName.length())); + } +} From 7b92958ac4abbc82b2ecbaa0074edf5fada9403b Mon Sep 17 00:00:00 2001 From: Soyeon Choe <77609591+soi-ha@users.noreply.github.com> Date: Thu, 25 Jul 2024 11:16:44 +0900 Subject: [PATCH 084/178] =?UTF-8?q?feat:=20=ED=96=89=EC=82=AC=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?(#107)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * style: eslint 적용 * chore: typescript with invalid interface loaded as resolver 해결을 위한 eslint-import-resolver-typescript 설치 * chore: SetInitialParticipatns & SetActionModalContent를 Modal의 index.ts에서 export 추가 * design: HDesignProvider 적용 * design: 행사 관리 페이지 퍼블리싱 * design: 초기 인원 설정 Modal 퍼블리싱 * design: 지출내역 생성 Modal 내부 퍼블리싱 * design: 인원 변동 내역 Modal 내부 퍼블리싱 * feat: TopNav 추가 및 props 추가 * design: BottomSheet 내부 퍼블리싱 (Input overflow시 scroll) * design: 행사 지출/인원 변동 내역 생성 퍼블리싱 * design: switch와 container의 gap 추가 * design: scroll시 모든 자식 요소가 안 보이는 에러 해결 * design: MainLayout 적용 및 root 태그에 height 적용 * design: 지출 내역 생성 Modal 내부 퍼블리싱 * design: 인원 변동 내역 생성 Modal 내부 퍼블리싱 * chore: develop 브랜치 merge로 인한 수정 * chore: 불필요한 import 삭제 * chore: haengdong-design 버전 업데이트 설치 * remove: 사용하지 않는 파일 제거 * chore: TopNav 수정된 디자인 시스템 설치 및 StepList 수정 주석 추가 * style: lint 적용 * feat: Input 값 입력시 다음 Input이 생성되는 hook 기능 구현 * feat: useDynamicInput에 auto focus 및 scrollIntoView 기능 추가 * feat: 초기 인원 설정 및 인원 변동 내역 Modal에 useDynamicInput 적용 * feat: 지출 내역에 대한 기능 구현 (useDynamicInputPairs 훅 생성) * chore: 불필요한 props 제거 및 backlog 주석 추가 * fix: BottomSheet의 onClick을 통해 submit되는 오류 수정 * fix: setParticipants를 분리하여 참여 인원 관리 * fix: setOrder를 분리하여 지출 내역 차수 관리 * chore: 사용하지 않는 상태 제거 * chore: haengdong-design 버전 업데이트 반영 * fix: 작성된 값을 수정할 수 없는 에러 해결 * chore: 에러 발생 수정에 대한 주석 추가 * chore: 디자인시스템 버전 업데이트 반영 --- client/eslint.config.mjs | 3 + client/package-lock.json | 8 +- client/package.json | 2 +- client/src/apis/request/bill.ts | 3 +- client/src/apis/request/event.ts | 3 +- client/src/apis/request/member.ts | 3 +- client/src/apis/request/report.ts | 3 +- client/src/apis/request/stepList.ts | 3 +- .../MemberReportList/MemberReportList.tsx | 3 +- client/src/components/Modal/Modal.tsx | 20 --- .../SetActionModalContent.style.ts | 16 ++ .../SetActionModalContent.style.tsx | 24 --- .../SetActionModalContent.tsx | 76 +++++---- .../SetPurchase.style.ts | 23 +++ .../SetActionModalContent/SetPurchase.tsx | 69 ++++---- .../UpdateParticipants.style.ts | 18 ++ .../UpdateParticipants.tsx | 76 +++++---- .../SetInitialParticipants.style.ts | 49 ++---- .../SetInitialParticipants.tsx | 75 +++++---- client/src/components/Modal/index.ts | 3 +- client/src/components/StepList/StepList.tsx | 3 +- client/src/components/Switch/Switch.style.tsx | 17 -- client/src/components/Switch/Switch.tsx | 28 ---- client/src/components/Switch/index.tsx | 1 - .../src/hooks/useDynamicAdditionalInput.tsx | 52 ++++++ client/src/hooks/useDynamicInputPairs.tsx | 42 +++++ .../useSearchMemberReportList.tsx | 5 +- client/src/hooks/useStepList/useStepList.tsx | 2 + client/src/index.css | 6 + client/src/pages/CreateEvent/CreateEvent.tsx | 1 + client/src/pages/Event/Event.style.ts | 22 +-- client/src/pages/Event/Event.tsx | 158 ++++++++++-------- client/src/pages/Home/HomeContent.tsx | 3 +- client/src/pages/Home/HomeLayout.tsx | 1 + 34 files changed, 459 insertions(+), 362 deletions(-) delete mode 100644 client/src/components/Modal/Modal.tsx create mode 100644 client/src/components/Modal/SetActionModalContent/SetActionModalContent.style.ts delete mode 100644 client/src/components/Modal/SetActionModalContent/SetActionModalContent.style.tsx create mode 100644 client/src/components/Modal/SetActionModalContent/SetPurchase.style.ts create mode 100644 client/src/components/Modal/SetActionModalContent/UpdateParticipants.style.ts delete mode 100644 client/src/components/Switch/Switch.style.tsx delete mode 100644 client/src/components/Switch/Switch.tsx delete mode 100644 client/src/components/Switch/index.tsx create mode 100644 client/src/hooks/useDynamicAdditionalInput.tsx create mode 100644 client/src/hooks/useDynamicInputPairs.tsx diff --git a/client/eslint.config.mjs b/client/eslint.config.mjs index 46d23de19..106f6ccde 100644 --- a/client/eslint.config.mjs +++ b/client/eslint.config.mjs @@ -32,6 +32,9 @@ export default [ 'react/react-in-jsx-scope': 'off', 'react/prop-types': 'off', 'react/jsx-uses-vars': 'error', + // '@typescript-eslint/no-use-before-define': ['error'], + // '@typescript-eslint/explicit-module-boundary-types': 'error', + // "import/no-unresolved": "error", 'import/order': [ 'error', { diff --git a/client/package-lock.json b/client/package-lock.json index d66f61a8b..4ee33aaae 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -12,7 +12,7 @@ "@emotion/react": "^11.11.4", "@types/dotenv-webpack": "^7.0.7", "dotenv-webpack": "^8.1.0", - "haengdong-design": "^0.1.20", + "haengdong-design": "^0.1.28", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.24.1" @@ -6274,9 +6274,9 @@ "dev": true }, "node_modules/haengdong-design": { - "version": "0.1.20", - "resolved": "https://registry.npmjs.org/haengdong-design/-/haengdong-design-0.1.20.tgz", - "integrity": "sha512-MB4L5lP0eDKhm5hU/XROKNE/H0pj9Zaf/uiLUUhtvOzS6bzHd2guYlE/LI0G2bvA7v65APD1Bzp3KXGi/Z8nNw==", + "version": "0.1.28", + "resolved": "https://registry.npmjs.org/haengdong-design/-/haengdong-design-0.1.28.tgz", + "integrity": "sha512-czidJMyGWLbdfrabj3SARWMS3fB26c1Fg43XxS7ognTc3mG37BqRe6coPKueU0onB4IoB+xhYZcmHJKIZwukLw==", "dependencies": { "@emotion/react": "^11.11.4", "@svgr/webpack": "^8.1.0", diff --git a/client/package.json b/client/package.json index 8155d4dc9..350a884ed 100644 --- a/client/package.json +++ b/client/package.json @@ -45,9 +45,9 @@ }, "dependencies": { "@emotion/react": "^11.11.4", - "haengdong-design": "^0.1.20", "@types/dotenv-webpack": "^7.0.7", "dotenv-webpack": "^8.1.0", + "haengdong-design": "^0.1.28", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.24.1" diff --git a/client/src/apis/request/bill.ts b/client/src/apis/request/bill.ts index 31c097276..2e364b944 100644 --- a/client/src/apis/request/bill.ts +++ b/client/src/apis/request/bill.ts @@ -1,8 +1,9 @@ +import {Bill} from 'types/stepList'; + import {BASE_URL} from '@apis/baseUrl'; import {TEMP_PREFIX} from '@apis/tempPrefix'; import {requestPost} from '@apis/fetcher'; import {WithEventId} from '@apis/withEventId.type'; -import {Bill} from 'types/stepList'; type RequestAddBillList = { BillList: Bill[]; diff --git a/client/src/apis/request/event.ts b/client/src/apis/request/event.ts index c941f31d4..f6ff6d56b 100644 --- a/client/src/apis/request/event.ts +++ b/client/src/apis/request/event.ts @@ -1,7 +1,8 @@ +import {StepList} from 'types/stepList'; + import {BASE_URL} from '@apis/baseUrl'; import {TEMP_PREFIX} from '@apis/tempPrefix'; import {requestGet} from '@apis/fetcher'; -import {StepList} from 'types/stepList'; type RequestCreateNewEvent = { name: string; diff --git a/client/src/apis/request/member.ts b/client/src/apis/request/member.ts index af8b6c689..252c85e11 100644 --- a/client/src/apis/request/member.ts +++ b/client/src/apis/request/member.ts @@ -1,8 +1,9 @@ +import {Member} from 'types/stepList'; + import {BASE_URL} from '@apis/baseUrl'; import {TEMP_PREFIX} from '@apis/tempPrefix'; import {requestPost} from '@apis/fetcher'; import {WithEventId} from '@apis/withEventId.type'; -import {Member} from 'types/stepList'; type RequestUpdateMemberList = { MemberList: Member[]; diff --git a/client/src/apis/request/report.ts b/client/src/apis/request/report.ts index cc9b0ad66..9b714752a 100644 --- a/client/src/apis/request/report.ts +++ b/client/src/apis/request/report.ts @@ -1,8 +1,9 @@ +import {MemberReport} from 'types/stepList'; + import {BASE_URL} from '@apis/baseUrl'; import {TEMP_PREFIX} from '@apis/tempPrefix'; import {requestGet} from '@apis/fetcher'; import {WithEventId} from '@apis/withEventId.type'; -import {MemberReport} from 'types/stepList'; type ResponseMemberReportList = { reports: MemberReport[]; diff --git a/client/src/apis/request/stepList.ts b/client/src/apis/request/stepList.ts index d696c69aa..60ad385e4 100644 --- a/client/src/apis/request/stepList.ts +++ b/client/src/apis/request/stepList.ts @@ -1,8 +1,9 @@ +import {Bill, Member, StepList} from 'types/stepList'; + import {BASE_URL} from '@apis/baseUrl'; import {TEMP_PREFIX} from '@apis/tempPrefix'; import {requestGet, requestPost} from '@apis/fetcher'; import {WithEventId} from '@apis/withEventId.type'; -import {Bill, Member, StepList} from 'types/stepList'; // TODO: (@weadie) 현재 토큰을 어떻게 관리할지.. 계속 사용되는데 export const requestStepList = async ({eventId}: WithEventId) => { diff --git a/client/src/components/MemberReportList/MemberReportList.tsx b/client/src/components/MemberReportList/MemberReportList.tsx index 17a26f9ca..ebf1cf72e 100644 --- a/client/src/components/MemberReportList/MemberReportList.tsx +++ b/client/src/components/MemberReportList/MemberReportList.tsx @@ -1,7 +1,8 @@ -import useSearchMemberReportList from '@hooks/useSearchMemberReportList/useSearchMemberReportList'; import {ExpenseList, Flex, Input} from 'haengdong-design'; import React, {useState} from 'react'; +import useSearchMemberReportList from '@hooks/useSearchMemberReportList/useSearchMemberReportList'; + const MemberReportList = () => { const [name, setName] = useState(''); const {memberReportSearchList} = useSearchMemberReportList({name, eventId: '므와아아아'}); diff --git a/client/src/components/Modal/Modal.tsx b/client/src/components/Modal/Modal.tsx deleted file mode 100644 index aaf0b8b6a..000000000 --- a/client/src/components/Modal/Modal.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import {css} from '@emotion/react'; - -import {modalBodyStyle, modalBackdropStyle} from './Modal.style'; - -interface ModalProps { - children: React.ReactNode; - onClose: () => void; -} - -const Modal = ({children, onClose}: ModalProps) => { - return ( - <> - <div css={modalBackdropStyle} onClick={onClose} /> - <div css={modalBodyStyle}>{children}</div> - </> - ); -}; - -export default Modal; diff --git a/client/src/components/Modal/SetActionModalContent/SetActionModalContent.style.ts b/client/src/components/Modal/SetActionModalContent/SetActionModalContent.style.ts new file mode 100644 index 000000000..560f672d5 --- /dev/null +++ b/client/src/components/Modal/SetActionModalContent/SetActionModalContent.style.ts @@ -0,0 +1,16 @@ +import {css} from '@emotion/react'; + +export const setActionModalContentStyle = css({ + display: 'flex', + flexDirection: 'column', + width: '100%', + height: '100%', + padding: '0 1.5rem', + gap: '1.5rem', +}); + +export const setActionModalContentSwitchContainerStyle = css({ + display: 'flex', + width: '100%', + justifyContent: 'space-between', +}); diff --git a/client/src/components/Modal/SetActionModalContent/SetActionModalContent.style.tsx b/client/src/components/Modal/SetActionModalContent/SetActionModalContent.style.tsx deleted file mode 100644 index 48e975e9c..000000000 --- a/client/src/components/Modal/SetActionModalContent/SetActionModalContent.style.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import {css} from '@emotion/react'; - -export const buttonStyle = (isActive: boolean) => css` - font-weight: ${isActive ? 'bold' : 'normal'}; - color: ${isActive ? '#333' : '#ccc'}; - padding: 10px; - cursor: pointer; -`; - -export const dividerStyle = css` - margin: 0 10px; - color: #ccc; -`; - -export const switchStyle = css` - display: flex; - align-items: center; -`; - -export const switchContainerStyle = css` - display: flex; - width: 100%; - justify-content: space-between; -`; diff --git a/client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx b/client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx index 2c293abc8..93a917652 100644 --- a/client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx +++ b/client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx @@ -1,58 +1,60 @@ import {useState} from 'react'; +import {BottomSheet, Switch} from 'haengdong-design'; -import {Switch} from '@components/Switch'; +import {InOutType, ParticipantType, PurchaseInformation} from '@pages/Event/Event'; import SetPurchase from './SetPurchase'; import UpdateParticipants from './UpdateParticipants'; -import {switchContainerStyle} from './SetActionModalContent.style'; +import {setActionModalContentStyle, setActionModalContentSwitchContainerStyle} from './SetActionModalContent.style'; -// type ActionType = '지출' | '인원'; +export type ActionType = '지출' | '인원'; interface SetActionModalContentProps { - setOpen: React.Dispatch<React.SetStateAction<boolean>>; participants: string[]; - setParticipants: React.Dispatch<React.SetStateAction<string[]>>; - purchaseInformation: any; - setPurchaseInformation: any; + openBottomSheet: boolean; + + setOpenBottomSheet: React.Dispatch<React.SetStateAction<boolean>>; + setOrder: React.Dispatch<React.SetStateAction<number>>; } const SetActionModalContent = ({ - setOpen, participants, - setParticipants, - purchaseInformation, - setPurchaseInformation, + openBottomSheet, + + setOpenBottomSheet, + setOrder, }: SetActionModalContentProps) => { - const [actionType, setActionType] = useState('지출'); - const [participantType, setParticipantType] = useState('늦참'); + const [action, setAction] = useState<ActionType>('지출'); + const [participantAction, setParticipantAction] = useState<InOutType>('탈주'); + + const handleActionTypeChange = (value: string) => { + setAction(value as ActionType); + }; + + const handleParticipantTypeChange = (value: string) => { + setParticipantAction(value as InOutType); + }; return ( - <> - <div css={switchContainerStyle}> - <Switch buttonList={['지출', '인원']} curSwitch={actionType} setSwitch={setActionType} /> - {actionType === '인원' && ( - <Switch buttonList={['늦참', '탈주']} curSwitch={participantType} setSwitch={setParticipantType} /> + <BottomSheet isOpened={openBottomSheet} onChangeClose={() => setOpenBottomSheet(false)}> + <div css={setActionModalContentStyle}> + <div css={setActionModalContentSwitchContainerStyle}> + <Switch value={action} onChange={handleActionTypeChange} values={['지출', '인원']} /> + {action === '인원' && ( + <Switch values={['늦참', '탈주']} value={participantAction} onChange={handleParticipantTypeChange} /> + )} + </div> + + {action === '지출' && <SetPurchase setOpenBottomSheet={setOpenBottomSheet} setOrder={setOrder} />} + {action === '인원' && ( + <UpdateParticipants + participantAction={participantAction} + participants={participants} + setOpenBottomSheet={setOpenBottomSheet} + /> )} </div> - - {actionType === '지출' && ( - <SetPurchase - setOpen={setOpen} - setPurchaseInformation={setPurchaseInformation} - purchaseInformation={purchaseInformation} - /> - )} - {actionType === '인원' && ( - <UpdateParticipants - setOpen={setOpen} - participantType={participantType} - participants={participants} - setParticipants={setParticipants} - setPurchaseInformation={setPurchaseInformation} - purchaseInformation={purchaseInformation} - /> - )} - </> + </BottomSheet> ); }; diff --git a/client/src/components/Modal/SetActionModalContent/SetPurchase.style.ts b/client/src/components/Modal/SetActionModalContent/SetPurchase.style.ts new file mode 100644 index 000000000..cc852da28 --- /dev/null +++ b/client/src/components/Modal/SetActionModalContent/SetPurchase.style.ts @@ -0,0 +1,23 @@ +import {css} from '@emotion/react'; + +export const setPurchaseStyle = () => + css({ + height: '100%', + }); + +export const setPurchaseInputContainerStyle = () => + css({ + display: 'flex', + height: '100%', + flexDirection: 'column', + gap: '1.5rem', + overflow: 'auto', + paddingBottom: '14rem', + }); + +export const setPurchaseInputStyle = () => + css({ + display: 'flex', + flexDirection: 'column', + gap: '0.5rem', + }); diff --git a/client/src/components/Modal/SetActionModalContent/SetPurchase.tsx b/client/src/components/Modal/SetActionModalContent/SetPurchase.tsx index 3112f2d41..515c048dd 100644 --- a/client/src/components/Modal/SetActionModalContent/SetPurchase.tsx +++ b/client/src/components/Modal/SetActionModalContent/SetPurchase.tsx @@ -1,42 +1,53 @@ -import {useState} from 'react'; +import {Input, FixedButton} from 'haengdong-design'; -import {PurchaseInformation} from '@pages/Event/Event'; +import useDynamicInputPairs from '@hooks/useDynamicInputPairs'; + +import {setPurchaseInputStyle, setPurchaseStyle, setPurchaseInputContainerStyle} from './SetPurchase.style'; interface SetPurchaseProps { - setOpen: React.Dispatch<React.SetStateAction<boolean>>; - setPurchaseInformation: any; - purchaseInformation: any; + setOpenBottomSheet: React.Dispatch<React.SetStateAction<boolean>>; + setOrder: React.Dispatch<React.SetStateAction<number>>; } -const SetPurchase = ({setOpen, setPurchaseInformation}: SetPurchaseProps) => { - const [newPurchaseInformation, setNewPurchaseInformation] = useState<PurchaseInformation>({ - name: '', - price: 0, - }); - - const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => { - setNewPurchaseInformation({...newPurchaseInformation, name: e.target.value}); - }; - - const handlePriceChange = (e: React.ChangeEvent<HTMLInputElement>) => { - setNewPurchaseInformation({...newPurchaseInformation, price: parseFloat(e.target.value)}); - }; +const SetPurchase = ({setOpenBottomSheet, setOrder}: SetPurchaseProps) => { + const {inputPairs, inputRefs, handleInputChange, handleInputBlur} = useDynamicInputPairs(); - const addPurchaseInformation = () => { - setPurchaseInformation((prev: PurchaseInformation[]) => [...prev, newPurchaseInformation]); - setOpen(false); + const handleSetPurchaseSubmit = () => { + setOrder(prev => prev + 1); + // TODO: (@soha) api 요청시 inputPairs를 보내면 됨 + setOpenBottomSheet(false); }; return ( - <> - <div style={{display: 'flex', flexDirection: 'column'}}> - <input type="text" value={newPurchaseInformation.name} onChange={handleNameChange} placeholder="지출 내역" /> - <input type="number" value={newPurchaseInformation.price} onChange={handlePriceChange} placeholder="금액" /> + <div css={setPurchaseStyle}> + <div css={setPurchaseInputContainerStyle}> + {inputPairs.map((pair, index) => ( + <div key={index} css={setPurchaseInputStyle}> + <Input + type="text" + value={pair.name} + onChange={e => handleInputChange(index, 'name', e.target.value)} + onBlur={() => handleInputBlur(index)} + placeholder="지출 내역" + ref={el => (inputRefs.current[index * 2] = el)} + /> + <Input + type="number" + value={pair.price} + onChange={e => handleInputChange(index, 'price', e.target.value)} + onBlur={() => handleInputBlur(index)} + placeholder="금액" + ref={el => (inputRefs.current[index * 2 + 1] = el)} + /> + </div> + ))} </div> - <button style={{backgroundColor: 'lightGreen'}} onClick={addPurchaseInformation}> - 지출 내역 작성 완료 - </button> - </> + <FixedButton + variants={inputPairs.length - 1 ? 'primary' : 'tertiary'} + children={'추가하기'} + onClick={handleSetPurchaseSubmit} + /> + </div> ); }; diff --git a/client/src/components/Modal/SetActionModalContent/UpdateParticipants.style.ts b/client/src/components/Modal/SetActionModalContent/UpdateParticipants.style.ts new file mode 100644 index 000000000..087e25a85 --- /dev/null +++ b/client/src/components/Modal/SetActionModalContent/UpdateParticipants.style.ts @@ -0,0 +1,18 @@ +import {css} from '@emotion/react'; + +export const updateParticipantsStyle = () => + css({ + display: 'flex', + flexDirection: 'column', + gap: '1.5rem', + height: '100%', + }); + +export const updateParticipantsInputStyle = () => + css({ + display: 'flex', + flexDirection: 'column', + gap: '1rem', + overflow: 'auto', + paddingBottom: '14rem', + }); diff --git a/client/src/components/Modal/SetActionModalContent/UpdateParticipants.tsx b/client/src/components/Modal/SetActionModalContent/UpdateParticipants.tsx index e64ceff53..72b86faa7 100644 --- a/client/src/components/Modal/SetActionModalContent/UpdateParticipants.tsx +++ b/client/src/components/Modal/SetActionModalContent/UpdateParticipants.tsx @@ -1,51 +1,55 @@ +import {Input, FixedButton} from 'haengdong-design'; import {useState} from 'react'; +import {InOutType} from '@pages/Event/Event'; + +import useDynamicInput from '@hooks/useDynamicAdditionalInput'; + +import {updateParticipantsInputStyle, updateParticipantsStyle} from './UpdateParticipants.style'; + interface UpdateParticipantsProps { - setOpen: React.Dispatch<React.SetStateAction<boolean>>; - participantType: string; participants: string[]; - setParticipants: React.Dispatch<React.SetStateAction<string[]>>; - setPurchaseInformation: any; - purchaseInformation: any; + participantAction: InOutType; + setOpenBottomSheet: React.Dispatch<React.SetStateAction<boolean>>; } -const UpdateParticipants = ({ - setPurchaseInformation, - purchaseInformation, - setOpen, - participantType, - participants, - setParticipants, -}: UpdateParticipantsProps) => { - const [name, setName] = useState(''); - - const updateParticipant = () => { - if (participantType === '늦참') { - if (participants.includes(name)) { - alert('이미 있는 사용자입니다.'); - return; - } +const UpdateParticipants = ({participantAction, participants, setOpenBottomSheet}: UpdateParticipantsProps) => { + const {inputs, inputRefs, handleInputChange, handleInputBlur, getNonEmptyInputs} = useDynamicInput(); - setParticipants([...participants, name]); - setPurchaseInformation([...purchaseInformation, {name, type: '늦참'}]); - } else if (participantType === '탈주') { - if (!participants.includes(name)) { - alert('그런 사용자는 없습니다. 올바른 이름을 입력해주세요.'); - return; + const handleUpdateParticipantsSubmit = () => { + const newParticipants = () => { + if (participantAction === '탈주') { + return participants.filter(participant => !getNonEmptyInputs().includes(participant)); + } else { + return [...participants, ...getNonEmptyInputs()]; } + }; - setParticipants(prev => prev.filter(participant => participant !== name)); - setPurchaseInformation([...purchaseInformation, {name, type: '탈주'}]); - } - - setName(''); - setOpen(false); + // TODO: (@soha) api 요청시 newParticipants()를 보내면 됨 + setOpenBottomSheet(false); }; return ( - <div style={{display: 'flex', flexDirection: 'column'}}> - <input onChange={event => setName(event.target.value)} value={name} /> - <button onClick={updateParticipant}>{participantType} 인원 확정</button> + <div css={updateParticipantsStyle}> + <div css={updateParticipantsInputStyle}> + {/* TODO: (@soha) Search로 변경하기 */} + {inputs.map((name, index) => ( + <Input + key={index} + placeholder="이름" + value={name} + type="text" + ref={el => (inputRefs.current[index] = el)} + onChange={e => handleInputChange(index, e.target.value)} + onBlur={() => handleInputBlur(index)} + /> + ))} + </div> + <FixedButton + variants={inputs.length - 1 ? 'primary' : 'tertiary'} + children={`${inputs.length - 1}명 ${participantAction}`} + onClick={handleUpdateParticipantsSubmit} + /> </div> ); }; diff --git a/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.style.ts b/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.style.ts index 7f666c8d1..f0f5bf996 100644 --- a/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.style.ts +++ b/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.style.ts @@ -1,35 +1,20 @@ import {css} from '@emotion/react'; -export const inputStyle = css` - width: 100%; - padding: 10px; - border: 1px solid #ccc; - border-radius: 10px; - margin-bottom: 10px; -`; +export const setInitialParticipantsStyle = () => + css({ + display: 'flex', + flexDirection: 'column', + gap: '1.5rem', + width: '100%', + height: '100%', + padding: '0 1.5rem', + }); -export const buttonStyle = (isActive: boolean) => css` - display: block; - width: 100%; - padding: 10px; - background-color: ${isActive ? '#B575FF' : '#e0e0e0'}; - border: none; - border-radius: 10px; - text-align: center; - color: ${isActive ? 'white' : '#999'}; - margin-top: 10px; -`; - -export const plusButtonStyle = css` - display: flex; - justify-content: center; - align-items: center; - width: 40px; - height: 40px; - background-color: #f5f5ff; - border: none; - border-radius: 50%; - color: #9e77ed; - font-size: 24px; - margin: 20px auto; -`; +export const setInitialParticipantsInputGroupStyle = () => + css({ + display: 'flex', + flexDirection: 'column', + gap: '1rem', + overflow: 'auto', + paddingBottom: '11rem', + }); diff --git a/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.tsx b/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.tsx index 3a9f11a69..15a0b0460 100644 --- a/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.tsx +++ b/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.tsx @@ -1,47 +1,52 @@ -import {useState} from 'react'; +import {Text, Input, BottomSheet, FixedButton} from 'haengdong-design'; -import {buttonStyle, inputStyle, plusButtonStyle} from './SetInitialParticipants.style'; +import useDynamicInput from '@hooks/useDynamicAdditionalInput'; + +import {setInitialParticipantsInputGroupStyle, setInitialParticipantsStyle} from './SetInitialParticipants.style'; interface SetInitialParticipantsProps { - setParticipantsAndModalClose: (participants: string[]) => void; + openBottomSheet: boolean; + setOpenBottomSheet: React.Dispatch<React.SetStateAction<boolean>>; + setParticipants: React.Dispatch<React.SetStateAction<string[]>>; } -const SetInitialParticipants = ({setParticipantsAndModalClose}: SetInitialParticipantsProps) => { - const [value, setValue] = useState(''); - const [participants, setParticipants] = useState<string[]>([]); - - const addParticipants = (event: React.FormEvent<HTMLFormElement>) => { - if (value === '') return; +const SetInitialParticipants = ({ + openBottomSheet, + setOpenBottomSheet, + setParticipants, +}: SetInitialParticipantsProps) => { + const {inputs, inputRefs, handleInputChange, handleInputBlur, getNonEmptyInputs} = useDynamicInput(); - event.preventDefault(); - setParticipants(prev => [...prev, value]); - setValue(''); + const handleSubmit = () => { + setParticipants(getNonEmptyInputs()); + // TODO: (@soha) api 요청시 getNonEmptyInputs() 보낼 형태 생성 + setOpenBottomSheet(false); }; return ( - <> - <h2>초기 인원 설정하기</h2> - {participants.map((participant, index) => ( - <input key={`${participant}-${index}`} type="text" value={participant} disabled /> - ))} - <form onSubmit={addParticipants}> - <input - type="text" - placeholder="이름" - css={inputStyle} - value={value} - onChange={event => setValue(event.target.value)} - /> - <button css={plusButtonStyle}>+</button> - </form> - <button - css={buttonStyle(participants.length !== 0)} - disabled={participants.length === 0} - onClick={() => setParticipantsAndModalClose(participants)} - > - 인원 설정 완료 - </button> - </> + <BottomSheet isOpened={openBottomSheet} onChangeClose={() => setOpenBottomSheet(false)}> + <div css={setInitialParticipantsStyle}> + <Text size="bodyBold">초기 인원 설정하기</Text> + <div css={setInitialParticipantsInputGroupStyle}> + {inputs.map((participant, index) => ( + <Input + key={index} + placeholder="이름" + type="text" + value={participant} + ref={el => (inputRefs.current[index] = el)} + onChange={e => handleInputChange(index, e.target.value)} + onBlur={() => handleInputBlur(index)} + /> + ))} + </div> + </div> + <FixedButton + variants={inputs.length - 1 ? 'primary' : 'tertiary'} + onClick={handleSubmit} + children={'인원 설정 완료'} + /> + </BottomSheet> ); }; diff --git a/client/src/components/Modal/index.ts b/client/src/components/Modal/index.ts index 1693a3eef..e5d5264cd 100644 --- a/client/src/components/Modal/index.ts +++ b/client/src/components/Modal/index.ts @@ -1 +1,2 @@ -export {default as Modal} from './Modal'; +export {default as SetInitialParticipants} from './SetInitialParticipants/SetInitialParticipants'; +export {default as SetActionModalContent} from './SetActionModalContent/SetActionModalContent'; diff --git a/client/src/components/StepList/StepList.tsx b/client/src/components/StepList/StepList.tsx index 2ea9c0bc5..76dedc41b 100644 --- a/client/src/components/StepList/StepList.tsx +++ b/client/src/components/StepList/StepList.tsx @@ -1,5 +1,6 @@ -import {useStepList} from '@hooks/useStepList/useStepList'; import {Flex, InOutItem, StepItem} from 'haengdong-design'; + +import {useStepList} from '@hooks/useStepList/useStepList'; import {MemberType} from 'types/stepList'; const StepList = () => { diff --git a/client/src/components/Switch/Switch.style.tsx b/client/src/components/Switch/Switch.style.tsx deleted file mode 100644 index 0e1b81b50..000000000 --- a/client/src/components/Switch/Switch.style.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import {css} from '@emotion/react'; - -export const buttonStyle = (isActive: boolean) => css` - font-weight: ${isActive ? 'bold' : 'normal'}; - color: ${isActive ? '#333' : '#ccc'}; - padding: 10px; - cursor: pointer; -`; - -export const dividerStyle = css` - color: #ccc; -`; - -export const switchStyle = css` - display: flex; - align-items: center; -`; diff --git a/client/src/components/Switch/Switch.tsx b/client/src/components/Switch/Switch.tsx deleted file mode 100644 index ba30ea320..000000000 --- a/client/src/components/Switch/Switch.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; - -import {buttonStyle, switchStyle} from './Switch.style'; - -interface SwitchProps { - buttonList: string[]; - initialButton?: string; - curSwitch: string; - setSwitch: React.Dispatch<React.SetStateAction<string>>; -} - -const Switch = ({buttonList, initialButton = buttonList[0], setSwitch, curSwitch}: SwitchProps) => { - const handleButtonClick = (type: string) => { - setSwitch(type); - }; - - return ( - <div css={switchStyle}> - {buttonList.map(buttonName => ( - <button css={buttonStyle(curSwitch === buttonName)} onClick={() => handleButtonClick(buttonName)}> - {buttonName} - </button> - ))} - </div> - ); -}; - -export default Switch; diff --git a/client/src/components/Switch/index.tsx b/client/src/components/Switch/index.tsx deleted file mode 100644 index 6c9915003..000000000 --- a/client/src/components/Switch/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export {default as Switch} from './Switch'; diff --git a/client/src/hooks/useDynamicAdditionalInput.tsx b/client/src/hooks/useDynamicAdditionalInput.tsx new file mode 100644 index 000000000..6bd592254 --- /dev/null +++ b/client/src/hooks/useDynamicAdditionalInput.tsx @@ -0,0 +1,52 @@ +import {useEffect, useRef, useState} from 'react'; + +const useDynamicInput = () => { + const [inputs, setInputs] = useState<string[]>(['']); + const inputRefs = useRef<(HTMLInputElement | null)[]>([]); + + // TODO: (@soha) 입력이 완료되고 중간에 값을 모두 지웠을 경우 Input이 없애지도록 수정하기 + const handleInputChange = (index: number, value: string) => { + const newInputs = [...inputs]; + newInputs[index] = value; + setInputs(newInputs); + }; + + const handleInputBlur = (index: number) => { + if (inputs[index].trim() === '') { + setInputs(prev => { + const newInputs = [...prev]; + newInputs[index] = ''; + return newInputs; + }); + } else if (inputs[index].trim() !== '' && index === inputs.length - 1) { + setInputs(prev => { + const newInputs = [...prev, '']; + newInputs[index] = inputs[index].trim(); + return newInputs; + }); + } + }; + + const getNonEmptyInputs = () => { + return inputs.filter(input => input.trim() !== ''); + }; + + useEffect(() => { + if (inputRefs.current.length > 0) { + const lastInput = inputRefs.current[inputRefs.current.length - 1]; + if (lastInput) { + lastInput.scrollIntoView({behavior: 'smooth', block: 'center'}); + } + } + }, [inputs]); + + return { + inputs, + inputRefs, + handleInputChange, + handleInputBlur, + getNonEmptyInputs, + }; +}; + +export default useDynamicInput; diff --git a/client/src/hooks/useDynamicInputPairs.tsx b/client/src/hooks/useDynamicInputPairs.tsx new file mode 100644 index 000000000..db5347dd8 --- /dev/null +++ b/client/src/hooks/useDynamicInputPairs.tsx @@ -0,0 +1,42 @@ +import {useEffect, useRef, useState} from 'react'; + +import {PurchaseInformation} from '@pages/Event/Event'; + +const useDynamicInputPairs = () => { + const [inputPairs, setInputPairs] = useState<PurchaseInformation[]>([{name: '', price: 0}]); + const inputRefs = useRef<(HTMLInputElement | null)[]>([]); + + const handleInputChange = (index: number, field: 'name' | 'price', value: string) => { + const newInputPairs = [...inputPairs]; + newInputPairs[index] = { + ...newInputPairs[index], + [field]: field === 'price' ? parseFloat(value) : value, + }; + setInputPairs(newInputPairs); + }; + + const handleInputBlur = (index: number) => { + const currentPair = inputPairs[index]; + if (currentPair.name.trim() === '' && currentPair.price === 0) { + setInputPairs(prev => prev.filter((_, i) => i !== index)); + } else if (currentPair.name.trim() !== '' && currentPair.price !== 0 && index === inputPairs.length - 1) { + setInputPairs(prev => [...prev, {name: '', price: 0}]); + } + }; + + useEffect(() => { + if (inputRefs.current.length > 0) { + const lastInputPair = inputRefs.current.slice(-2); + lastInputPair.forEach(ref => ref?.scrollIntoView({behavior: 'smooth', block: 'center'})); + } + }, [inputPairs]); + + return { + inputPairs, + inputRefs, + handleInputChange, + handleInputBlur, + }; +}; + +export default useDynamicInputPairs; diff --git a/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.tsx b/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.tsx index bdd1e3cf2..589317f7d 100644 --- a/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.tsx +++ b/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.tsx @@ -1,9 +1,12 @@ import {useEffect, useState} from 'react'; + import {MemberReport} from 'types/stepList'; -import memberReportSearchJsonList from '@mocks/memberReportSearchList.json'; import {requestMemberReportList} from '@apis/request/report'; + import {WithEventId} from '@apis/withEventId.type'; +import memberReportSearchJsonList from '@mocks/memberReportSearchList.json'; + const memberReportSearchMockList = memberReportSearchJsonList as MemberReport[]; type UseSearchMemberReportListParams = { diff --git a/client/src/hooks/useStepList/useStepList.tsx b/client/src/hooks/useStepList/useStepList.tsx index 842794f0f..9adb2d684 100644 --- a/client/src/hooks/useStepList/useStepList.tsx +++ b/client/src/hooks/useStepList/useStepList.tsx @@ -1,5 +1,7 @@ import {PropsWithChildren, createContext, useEffect, useState} from 'react'; + import {BillAction, MemberType, StepList} from 'types/stepList'; + import stepListJsonData from '@mocks/stepList.json'; const stepListMockData = stepListJsonData as StepList; diff --git a/client/src/index.css b/client/src/index.css index 936bdd319..8ebdb5ba8 100644 --- a/client/src/index.css +++ b/client/src/index.css @@ -7,3 +7,9 @@ body { section { width: 100%; } + +#root { + display: flex; + flex-direction: column; + height: 100%; +} diff --git a/client/src/pages/CreateEvent/CreateEvent.tsx b/client/src/pages/CreateEvent/CreateEvent.tsx index eb25c1faf..9697200e0 100644 --- a/client/src/pages/CreateEvent/CreateEvent.tsx +++ b/client/src/pages/CreateEvent/CreateEvent.tsx @@ -1,5 +1,6 @@ import {useState} from 'react'; import {useNavigate} from 'react-router-dom'; + import {ROUTER_URLS} from '@constants/routerUrls'; const CreateEvent = () => { diff --git a/client/src/pages/Event/Event.style.ts b/client/src/pages/Event/Event.style.ts index 517466c92..15e2443b4 100644 --- a/client/src/pages/Event/Event.style.ts +++ b/client/src/pages/Event/Event.style.ts @@ -1,17 +1,9 @@ import {css} from '@emotion/react'; -export const orderHeaderStyle = css` - display: flex; - justify-content: space-between; - align-items: center; - - width: 100%; -`; - -export const orderFooterStyle = css` - display: flex; - justify-content: space-between; - align-items: center; - - width: 100%; -`; +export const ReceiptStyle = () => + css({ + display: 'flex', + flexDirection: 'column', + gap: '8px', + padding: '0 8px', + }); diff --git a/client/src/pages/Event/Event.tsx b/client/src/pages/Event/Event.tsx index bded81860..edc95d5b4 100644 --- a/client/src/pages/Event/Event.tsx +++ b/client/src/pages/Event/Event.tsx @@ -1,93 +1,105 @@ import {useState} from 'react'; -import {useParams} from 'react-router-dom'; +import {TopNav, Title, FixedButton, StepItem, InOutItem, MainLayout} from 'haengdong-design'; -import {SetInitialParticipants} from '@components/Modal/SetInitialParticipants'; -import {SetActionModalContent} from '@components/Modal/SetActionModalContent'; +import {SetActionModalContent, SetInitialParticipants} from '@components/Modal'; -import {Modal} from '@components/Modal'; - -import {orderHeaderStyle} from './Event.style'; +import {ReceiptStyle} from './Event.style'; export type PurchaseInformation = { name: string; price: number; }; -type ParticipantType = { +export type InOutType = '늦참' | '탈주'; + +export type ParticipantType = { name: string; - type: '늦참' | '탈주'; + type: InOutType; }; -const Event = () => { - const {eventId} = useParams(); - const [open, setOpen] = useState(false); - const [participants, setParticipants] = useState<string[]>([]); - const [order, setOrder] = useState(0); +interface ModalRenderingProps { + participants: string[]; + openBottomSheet: boolean; + + setOrder: React.Dispatch<React.SetStateAction<number>>; + setOpenBottomSheet: React.Dispatch<React.SetStateAction<boolean>>; + setParticipants: React.Dispatch<React.SetStateAction<string[]>>; +} - const [purchaseInformation, setPurchaseInformation] = useState<(PurchaseInformation | ParticipantType)[]>([ - { - name: '', - price: 0, - } as PurchaseInformation, - ]); +const ModalRendering = ({ + participants, + setOrder, + setOpenBottomSheet, + setParticipants, + openBottomSheet, +}: ModalRenderingProps) => { + switch (participants.length) { + case 0: + return ( + <SetInitialParticipants + setParticipants={setParticipants} + setOpenBottomSheet={setOpenBottomSheet} + openBottomSheet={openBottomSheet} + /> + ); - const setParticipantsAndModalClose = (participants: string[]) => { - setParticipants(participants); - setOrder(1); - setOpen(false); - }; + default: + return ( + <SetActionModalContent + setOrder={setOrder} + participants={participants} + setOpenBottomSheet={setOpenBottomSheet} + openBottomSheet={openBottomSheet} + /> + ); + } +}; + +const Event = () => { + const [openBottomSheet, setOpenBottomSheet] = useState(false); + const [participants, setParticipants] = useState<string[]>([]); + const [order, setOrder] = useState<number>(0); return ( - <section> - <h1>{eventId}</h1> - <h3>“초기인원 설정하기” 버튼을 눌러서 행사 초기 인원을 설정해 주세요.</h3> - {order > 0 && ( - <article> - <header css={orderHeaderStyle}> - <h4>{`${order}차`}</h4> - <p>{`${participants.length}명`}</p> - </header> - {purchaseInformation.map((information, index) => ( - <section key={index} style={{padding: '10px'}}> - {'type' in information ? ( - <> - <h5> - {information.name} {information.type}입니다. - </h5> - </> - ) : ( - <> - <h5>{information.name}</h5> - <p>{information.price.toLocaleString()}원</p> - </> - )} - </section> - ))} - {/* <footer css={orderFooterStyle}> - <h6>총액</h6> - <p>{purchaseInformation.reduce((total, info) => 'price' in info ? total + info.price : total, 0).toLocaleString()}원</p> - </footer> */} - </article> - )} - <button onClick={() => setOpen(prev => !prev)}> - {participants.length === 0 ? '초기인원 설정하기' : '행동 추가하기'} - </button> - {open && ( - <Modal onClose={() => setOpen(false)}> - {participants.length === 0 ? ( - <SetInitialParticipants setParticipantsAndModalClose={setParticipantsAndModalClose} /> - ) : ( - <SetActionModalContent - setOpen={setOpen} - participants={participants} - setParticipants={setParticipants} - purchaseInformation={purchaseInformation} - setPurchaseInformation={setPurchaseInformation} + <MainLayout backgroundColor="gray"> + <TopNav navType={'home'} /> + <Title + title="행동대장 야유회" + description="“초기인원 설정하기” 버튼을 눌러서 행사 초기 인원을 설정해 주세요." + // TODO: (@soha) price 생성시 총 가격 생기기 + price={20000} + /> + <section css={ReceiptStyle}> + {order > 0 && ( + // TODO: (@soha) StepList로 변경하기 + // TODO: (@soha) order가 0일때 기본 Step 뜨기 + <> + <StepItem + name={`${order}차`} + personCount={participants.length} + bills={[ + {name: 'QWER', price: 12000, hasDragHandle: true}, + {name: '배고파요', price: 12000, hasDragHandle: true}, + ]} /> - )} - </Modal> - )} - </section> + <InOutItem names={['감자', '고구마']} inOutType={'OUT'} hasDragHandle={true} /> + </> + )} + {/* TODO: (@soha) 추후 버튼 width 화면에 맞게 수정 */} + <FixedButton + children={participants.length === 0 ? '초기인원 설정하기' : '행동 추가하기'} + onClick={() => setOpenBottomSheet(prev => !prev)} + /> + {openBottomSheet && + ModalRendering({ + participants, + setOrder, + setParticipants, + setOpenBottomSheet, + openBottomSheet, + })} + </section> + </MainLayout> ); }; diff --git a/client/src/pages/Home/HomeContent.tsx b/client/src/pages/Home/HomeContent.tsx index c13829222..171729636 100644 --- a/client/src/pages/Home/HomeContent.tsx +++ b/client/src/pages/Home/HomeContent.tsx @@ -1,7 +1,8 @@ +import {Tab, Tabs, Title} from 'haengdong-design'; + import MemberReportList from '@components/MemberReportList/MemberReportList'; import StepList from '@components/StepList/StepList'; import {useStepList} from '@hooks/useStepList/useStepList'; -import {Tab, Tabs, Title} from 'haengdong-design'; const HomeContent = () => { const {getTotalPrice} = useStepList(); diff --git a/client/src/pages/Home/HomeLayout.tsx b/client/src/pages/Home/HomeLayout.tsx index c204f3da1..8cae579d6 100644 --- a/client/src/pages/Home/HomeLayout.tsx +++ b/client/src/pages/Home/HomeLayout.tsx @@ -1,4 +1,5 @@ import {Flex, MainLayout, TopNav} from 'haengdong-design'; + import {StepListProvider} from '@hooks/useStepList/useStepList'; import HomeContent from './HomeContent'; From c85f71eb60c1e0791d44935cf53901656c957dab Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Thu, 25 Jul 2024 13:10:58 +0900 Subject: [PATCH 085/178] =?UTF-8?q?fix:=20=EC=98=88=EC=99=B8=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=A0=95=EC=9D=98=ED=95=9C=20=EB=A9=94=EC=84=B8?= =?UTF-8?q?=EC=A7=80=EB=A5=BC=20=EA=BA=BC=EB=82=B4=EC=A7=80=20=EB=AA=BB?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EC=98=A4=EB=A5=98=20=ED=95=B4=EA=B2=B0=20?= =?UTF-8?q?(#111)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/server/haengdong/exception/ErrorResponse.java | 4 ++-- .../haengdong/exception/GlobalExceptionHandler.java | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/server/src/main/java/server/haengdong/exception/ErrorResponse.java b/server/src/main/java/server/haengdong/exception/ErrorResponse.java index 5d1e33c9b..c797b811a 100644 --- a/server/src/main/java/server/haengdong/exception/ErrorResponse.java +++ b/server/src/main/java/server/haengdong/exception/ErrorResponse.java @@ -4,7 +4,7 @@ public record ErrorResponse( String message ) { - public static ErrorResponse of(HaengdongErrorCode errorCode) { - return new ErrorResponse(errorCode.getMessage()); + public static ErrorResponse of(String message) { + return new ErrorResponse(message); } } diff --git a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java index 7985721cd..bb3138cc7 100644 --- a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java +++ b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java @@ -15,7 +15,7 @@ public class GlobalExceptionHandler { @ExceptionHandler(HttpRequestMethodNotSupportedException.class) public ResponseEntity<ErrorResponse> haengdongException() { return ResponseEntity.badRequest() - .body(ErrorResponse.of(HaengdongErrorCode.BAD_REQUEST)); + .body(ErrorResponse.of(HaengdongErrorCode.BAD_REQUEST.getMessage())); } @ExceptionHandler(MethodArgumentNotValidException.class) @@ -25,19 +25,19 @@ public ResponseEntity<ErrorResponse> handleMethodArgumentNotValidException(Metho .collect(Collectors.joining(", ")); return ResponseEntity.badRequest() - .body(new ErrorResponse(errorMessage)); + .body(ErrorResponse.of(errorMessage)); } @ExceptionHandler(HaengdongException.class) public ResponseEntity<ErrorResponse> haengdongException(HaengdongException e) { return ResponseEntity.status(e.getStatusCode()) - .body(ErrorResponse.of(e.getErrorCode())); + .body(ErrorResponse.of(e.getMessage())); } @ExceptionHandler(Exception.class) public ResponseEntity<ErrorResponse> handleException(Exception e) { log.error(e.getMessage(), e); return ResponseEntity.internalServerError() - .body(ErrorResponse.of(HaengdongErrorCode.INTERNAL_SERVER_ERROR)); + .body(ErrorResponse.of(HaengdongErrorCode.INTERNAL_SERVER_ERROR.getMessage())); } } From 97bd3e6a59aaccc861663864e2dca6209dbe8916 Mon Sep 17 00:00:00 2001 From: Soyeon Choe <77609591+soi-ha@users.noreply.github.com> Date: Thu, 25 Jul 2024 13:23:56 +0900 Subject: [PATCH 086/178] =?UTF-8?q?feat:=20=ED=8D=BC=EB=B8=94=EB=A6=AC?= =?UTF-8?q?=EC=8B=B1=EB=90=9C=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EB=A7=A4?= =?UTF-8?q?=EB=81=84=EB=9F=BD=EA=B2=8C=20=EC=97=B0=EA=B2=B0=20(#114)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: 디자인시스템 업데이트 반영 * feat: fixed button 클릭시 router 반영 * feat: 총 지출 금액 추가 및 StepList 연결 --- client/package-lock.json | 8 ++++---- client/package.json | 2 +- client/src/constants/routerUrls.ts | 2 +- client/src/pages/Create/Complete.tsx | 2 +- client/src/pages/Create/Name.tsx | 2 +- client/src/pages/Event/Event.tsx | 24 ++++++++++-------------- 6 files changed, 18 insertions(+), 22 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index 4ee33aaae..8bc10061f 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -12,7 +12,7 @@ "@emotion/react": "^11.11.4", "@types/dotenv-webpack": "^7.0.7", "dotenv-webpack": "^8.1.0", - "haengdong-design": "^0.1.28", + "haengdong-design": "^0.1.29", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.24.1" @@ -6274,9 +6274,9 @@ "dev": true }, "node_modules/haengdong-design": { - "version": "0.1.28", - "resolved": "https://registry.npmjs.org/haengdong-design/-/haengdong-design-0.1.28.tgz", - "integrity": "sha512-czidJMyGWLbdfrabj3SARWMS3fB26c1Fg43XxS7ognTc3mG37BqRe6coPKueU0onB4IoB+xhYZcmHJKIZwukLw==", + "version": "0.1.29", + "resolved": "https://registry.npmjs.org/haengdong-design/-/haengdong-design-0.1.29.tgz", + "integrity": "sha512-yBxmS8PBYOMG6scumzeey2LQMSvlB5kqyd/pIP/ID4WRkvwVo8ScFYO6iV8odFINt4I1Dx2aC/itdk74Pyvv4A==", "dependencies": { "@emotion/react": "^11.11.4", "@svgr/webpack": "^8.1.0", diff --git a/client/package.json b/client/package.json index 350a884ed..fed2f5249 100644 --- a/client/package.json +++ b/client/package.json @@ -47,7 +47,7 @@ "@emotion/react": "^11.11.4", "@types/dotenv-webpack": "^7.0.7", "dotenv-webpack": "^8.1.0", - "haengdong-design": "^0.1.28", + "haengdong-design": "^0.1.29", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.24.1" diff --git a/client/src/constants/routerUrls.ts b/client/src/constants/routerUrls.ts index f0a910d5b..228e25c7c 100644 --- a/client/src/constants/routerUrls.ts +++ b/client/src/constants/routerUrls.ts @@ -3,6 +3,6 @@ export const ROUTER_URLS = { eventCreateName: '/event/create/name', eventCreateComplete: '/event/create/complete', event: '/event', - eventManage: '/event/:eventId', + eventManage: '/event/:eventId/admin', home: '/event/:eventId/home', }; diff --git a/client/src/pages/Create/Complete.tsx b/client/src/pages/Create/Complete.tsx index c2f499cb6..b4496d0cd 100644 --- a/client/src/pages/Create/Complete.tsx +++ b/client/src/pages/Create/Complete.tsx @@ -29,7 +29,7 @@ const CompleteCreateEvent = () => { description="행사가 성공적으로 개시됐어요 :) 행사 링크를 통해서 참여자 관리가 가능해요. 관리를 위해서 행사 관리 링크를 보관해 주세요." /> - <FixedButton onClick={() => navigate(`${ROUTER_URLS.event}/${url}`)}>관리 페이지로 이동</FixedButton> + <FixedButton onClick={() => navigate(`${ROUTER_URLS.event}/${url}/admin`)}>관리 페이지로 이동</FixedButton> </MainLayout> ); }; diff --git a/client/src/pages/Create/Name.tsx b/client/src/pages/Create/Name.tsx index ee847e258..8a1261662 100644 --- a/client/src/pages/Create/Name.tsx +++ b/client/src/pages/Create/Name.tsx @@ -27,7 +27,7 @@ const CreateEvent = () => { onChange={event => setEventTitle(event.target.value)} placeholder="ex) 행동대장 야유회" /> - <FixedButton>행동 개시!</FixedButton> + <FixedButton onClick={() => navigate(ROUTER_URLS.eventCreateComplete)}>행동 개시!</FixedButton> </form> </MainLayout> ); diff --git a/client/src/pages/Event/Event.tsx b/client/src/pages/Event/Event.tsx index edc95d5b4..79c1f9950 100644 --- a/client/src/pages/Event/Event.tsx +++ b/client/src/pages/Event/Event.tsx @@ -1,6 +1,10 @@ import {useState} from 'react'; import {TopNav, Title, FixedButton, StepItem, InOutItem, MainLayout} from 'haengdong-design'; +import StepList from '@components/StepList/StepList'; +import {useStepList} from '@hooks/useStepList/useStepList'; +import {StepListProvider} from '@hooks/useStepList/useStepList'; + import {SetActionModalContent, SetInitialParticipants} from '@components/Modal'; import {ReceiptStyle} from './Event.style'; @@ -60,30 +64,22 @@ const Event = () => { const [participants, setParticipants] = useState<string[]>([]); const [order, setOrder] = useState<number>(0); + const {getTotalPrice} = useStepList(); + return ( <MainLayout backgroundColor="gray"> <TopNav navType={'home'} /> <Title title="행동대장 야유회" description="“초기인원 설정하기” 버튼을 눌러서 행사 초기 인원을 설정해 주세요." - // TODO: (@soha) price 생성시 총 가격 생기기 - price={20000} + price={getTotalPrice()} /> <section css={ReceiptStyle}> {order > 0 && ( - // TODO: (@soha) StepList로 변경하기 // TODO: (@soha) order가 0일때 기본 Step 뜨기 - <> - <StepItem - name={`${order}차`} - personCount={participants.length} - bills={[ - {name: 'QWER', price: 12000, hasDragHandle: true}, - {name: '배고파요', price: 12000, hasDragHandle: true}, - ]} - /> - <InOutItem names={['감자', '고구마']} inOutType={'OUT'} hasDragHandle={true} /> - </> + <StepListProvider> + <StepList /> + </StepListProvider> )} {/* TODO: (@soha) 추후 버튼 width 화면에 맞게 수정 */} <FixedButton From 3cb6872a88a39a1915c81488329729d8fc51c6a5 Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Thu, 25 Jul 2024 15:17:29 +0900 Subject: [PATCH 087/178] =?UTF-8?q?refactor:=20=EC=9D=B8=EC=9B=90=20?= =?UTF-8?q?=EB=B3=80=EB=8F=99=20=EC=9A=94=EC=B2=AD=20=ED=98=95=ED=83=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20(#117)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/MemberActionSaveRequest.java | 10 ---------- .../request/MemberActionsSaveRequest.java | 12 +++++++++--- .../presentation/MemberActionControllerTest.java | 11 ++++------- 3 files changed, 13 insertions(+), 20 deletions(-) delete mode 100644 server/src/main/java/server/haengdong/presentation/request/MemberActionSaveRequest.java diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberActionSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberActionSaveRequest.java deleted file mode 100644 index a69c51d41..000000000 --- a/server/src/main/java/server/haengdong/presentation/request/MemberActionSaveRequest.java +++ /dev/null @@ -1,10 +0,0 @@ -package server.haengdong.presentation.request; - -import server.haengdong.application.request.MemberActionSaveAppRequest; - -public record MemberActionSaveRequest(String name, String status) { - - public MemberActionSaveAppRequest toAppRequest() { - return new MemberActionSaveAppRequest(name, status); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java index bfe80f0ee..0b3fcebae 100644 --- a/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java @@ -1,14 +1,20 @@ package server.haengdong.presentation.request; +import jakarta.validation.constraints.NotBlank; import java.util.List; import server.haengdong.application.request.MemberActionSaveAppRequest; import server.haengdong.application.request.MemberActionsSaveAppRequest; -public record MemberActionsSaveRequest(List<MemberActionSaveRequest> actions) { +public record MemberActionsSaveRequest( + List<String> members, + + @NotBlank + String status +) { public MemberActionsSaveAppRequest toAppRequest() { - List<MemberActionSaveAppRequest> appRequests = actions.stream() - .map(MemberActionSaveRequest::toAppRequest) + List<MemberActionSaveAppRequest> appRequests = members.stream() + .map(name -> new MemberActionSaveAppRequest(name, status)) .toList(); return new MemberActionsSaveAppRequest(appRequests); diff --git a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java index be8b89182..ad8787cc6 100644 --- a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java @@ -20,7 +20,6 @@ import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import server.haengdong.application.MemberActionService; import server.haengdong.application.response.CurrentMemberAppResponse; -import server.haengdong.presentation.request.MemberActionSaveRequest; import server.haengdong.presentation.request.MemberActionsSaveRequest; @WebMvcTest(MemberActionController.class) @@ -38,11 +37,8 @@ class MemberActionControllerTest { @DisplayName("참여자 행동을 추가한다.") @Test void saveMemberActionTest() throws Exception { - MemberActionsSaveRequest memberActionsSaveRequest = new MemberActionsSaveRequest(List.of( - new MemberActionSaveRequest("웨디", "IN"), - new MemberActionSaveRequest("소하", "IN"), - new MemberActionSaveRequest("토다리", "IN"), - new MemberActionSaveRequest("쿠키", "IN"))); + MemberActionsSaveRequest memberActionsSaveRequest = new MemberActionsSaveRequest( + List.of("웨디", "소하", "토다리", "쿠키"), "IN"); String requestBody = objectMapper.writeValueAsString(memberActionsSaveRequest); @@ -56,7 +52,8 @@ void saveMemberActionTest() throws Exception { @DisplayName("현재 참여 인원을 조회합니다.") @Test void getCurrentMembers() throws Exception { - List<CurrentMemberAppResponse> currentMemberAppResponses = List.of(new CurrentMemberAppResponse("소하"), new CurrentMemberAppResponse("토다리")); + List<CurrentMemberAppResponse> currentMemberAppResponses = List.of( + new CurrentMemberAppResponse("소하"), new CurrentMemberAppResponse("토다리")); given(memberActionService.getCurrentMembers(any())).willReturn(currentMemberAppResponses); From d943520138de321bfd74211348a5fd2599fe74b5 Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Thu, 25 Jul 2024 18:05:13 +0900 Subject: [PATCH 088/178] =?UTF-8?q?=08feat:=20=EC=95=A1=EC=85=98=20?= =?UTF-8?q?=EC=9D=B4=EB=A0=A5=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20(#76)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 액션 이력 조회 기능 구현 Co-authored-by: 3juhwan <13selfesteem91@naver.com> * feat: 액션 이력 조회 반환 형식 변경 * test: 액션 이력 조회 테스트 삭제 --------- Co-authored-by: 3juhwan <13selfesteem91@naver.com> --- .../haengdong/application/EventService.java | 52 +++++++++++++++ .../response/ActionAppResponse.java | 54 ++++++++++++++++ .../presentation/EventController.java | 8 +++ .../presentation/response/ActionResponse.java | 20 ++++++ .../response/ActionsResponse.java | 28 +++++++++ .../presentation/response/StepResponse.java | 63 +++++++++++++++++++ .../application/EventServiceTest.java | 51 +++++++++++++++ .../response/StepResponseTest.java | 57 +++++++++++++++++ 8 files changed, 333 insertions(+) create mode 100644 server/src/main/java/server/haengdong/application/response/ActionAppResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/ActionResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/StepResponse.java create mode 100644 server/src/test/java/server/haengdong/presentation/response/StepResponseTest.java diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java index dee023fbc..94c9dbda1 100644 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -1,10 +1,18 @@ package server.haengdong.application; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.response.ActionAppResponse; import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.domain.event.EventTokenProvider; @@ -17,6 +25,8 @@ public class EventService { private final EventRepository eventRepository; private final EventTokenProvider eventTokenProvider; + private final BillActionRepository billActionRepository; + private final MemberActionRepository memberActionRepository; public EventAppResponse saveEvent(EventAppRequest request) { String token = eventTokenProvider.createToken(); @@ -32,4 +42,46 @@ public EventDetailAppResponse findEvent(String token) { return EventDetailAppResponse.of(event); } + + public List<ActionAppResponse> findActions(String token) { + Event event = eventRepository.findByToken(token).orElseThrow(() -> new IllegalArgumentException("")); + + List<BillAction> billActions = billActionRepository.findByAction_Event(event).stream() + .sorted(Comparator.comparing(BillAction::getSequence)).toList(); + List<MemberAction> memberActions = memberActionRepository.findAllByEvent(event).stream() + .sorted(Comparator.comparing(MemberAction::getSequence)).toList(); + + return getActionAppResponses(billActions, memberActions); + } + + private List<ActionAppResponse> getActionAppResponses( + List<BillAction> billActions, + List<MemberAction> memberActions + ) { + int billActionIndex = 0; + int memberActionIndex = 0; + List<ActionAppResponse> actionAppResponses = new ArrayList<>(); + + while (billActionIndex < billActions.size() && memberActionIndex < memberActions.size()) { + BillAction billAction = billActions.get(billActionIndex); + MemberAction memberAction = memberActions.get(memberActionIndex); + if (billAction.getSequence() < memberAction.getSequence()) { + actionAppResponses.add(ActionAppResponse.of(billAction)); + billActionIndex++; + } else { + actionAppResponses.add(ActionAppResponse.of(memberAction)); + memberActionIndex++; + } + } + while (billActionIndex < billActions.size()) { + BillAction billAction = billActions.get(billActionIndex++); + actionAppResponses.add(ActionAppResponse.of(billAction)); + } + while (memberActionIndex < memberActions.size()) { + MemberAction memberAction = memberActions.get(memberActionIndex++); + actionAppResponses.add(ActionAppResponse.of(memberAction)); + } + + return actionAppResponses; + } } diff --git a/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java b/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java new file mode 100644 index 000000000..a1abcc35b --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java @@ -0,0 +1,54 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionStatus; + +public record ActionAppResponse( + Long actionId, + String name, + Long price, + Long sequence, + ActionType actionType +) { + + public static ActionAppResponse of(BillAction billAction) { + return new ActionAppResponse( + billAction.getAction().getId(), + billAction.getTitle(), + billAction.getPrice(), + billAction.getSequence(), + ActionType.BILL + ); + } + + public static ActionAppResponse of(MemberAction memberAction) { + MemberActionStatus status = memberAction.getStatus(); + + return new ActionAppResponse( + memberAction.getAction().getId(), + memberAction.getMemberName(), + null, + memberAction.getSequence(), + ActionType.of(status) + ); + } + + public String actionTypeName() { + return actionType.name(); + } + + public enum ActionType { + BILL, + IN, + OUT, + ; + + private static ActionType of(MemberActionStatus memberActionStatus) { + if (MemberActionStatus.IN == memberActionStatus) { + return IN; + } + return OUT; + } + } +} diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java index 260253e8b..9fbe098ce 100644 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -12,6 +12,7 @@ import server.haengdong.presentation.request.EventSaveRequest; import server.haengdong.presentation.response.EventDetailResponse; import server.haengdong.presentation.response.EventResponse; +import server.haengdong.presentation.response.StepResponse; @RequiredArgsConstructor @RestController @@ -32,4 +33,11 @@ public ResponseEntity<EventDetailResponse> findEvent(@PathVariable("eventId") St return ResponseEntity.ok(eventDetailResponse); } + + @GetMapping("/api/events/{eventId}/actions") + public ResponseEntity<StepResponse> findActions(@PathVariable("eventId") String token) { + StepResponse stepResponse = StepResponse.of(eventService.findActions(token)); + + return ResponseEntity.ok(stepResponse); + } } diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java b/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java new file mode 100644 index 000000000..a58e60186 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java @@ -0,0 +1,20 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.ActionAppResponse; + +public record ActionResponse( + Long actionId, + String name, + Long price, + Long sequence +) { + + public static ActionResponse of(ActionAppResponse actionAppResponse) { + return new ActionResponse( + actionAppResponse.actionId(), + actionAppResponse.name(), + actionAppResponse.price(), + actionAppResponse.sequence() + ); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java b/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java new file mode 100644 index 000000000..188c48dc9 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java @@ -0,0 +1,28 @@ +package server.haengdong.presentation.response; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import server.haengdong.application.response.ActionAppResponse; + +public record ActionsResponse( + String type, + String stepName, + Set<String> members, + List<ActionResponse> actions +) { + + public static ActionsResponse of(List<ActionAppResponse> actions, Set<String> members) { + List<ActionResponse> actionResponses = actions.stream() + .map(ActionResponse::of) + .toList(); + + String actionType = actions.get(0).actionTypeName(); + return new ActionsResponse( + actionType, + null, + new HashSet<>(members), + actionResponses + ); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/StepResponse.java b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java new file mode 100644 index 000000000..76f92ad53 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java @@ -0,0 +1,63 @@ +package server.haengdong.presentation.response; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import server.haengdong.application.response.ActionAppResponse; + +public record StepResponse( + List<ActionsResponse> steps +) { + + public static StepResponse of(List<ActionAppResponse> actions) { + List<ActionsResponse> actionsResponse = new ArrayList<>(); + Set<String> members = new HashSet<>(); + ActionAppResponse firstAction = getFirstAction(actions); + List<ActionAppResponse> group = new ArrayList<>(); + group.add(firstAction); + String currentActionType = firstAction.actionTypeName(); + members.add(firstAction.name()); + + for (int i = 1; i < actions.size(); i++) { + ActionAppResponse action = actions.get(i); + String typeName = action.actionTypeName(); + if (currentActionType.equals(typeName)) { + if (typeName.equals("IN")) { + members.add(action.name()); + } + if (typeName.equals("OUT")) { + members.remove(action.name()); + } + group.add(action); + continue; + } + if (currentActionType.equals("BILL")) { + actionsResponse.add(ActionsResponse.of(group, members)); + } else { + actionsResponse.add(ActionsResponse.of(group, Set.of())); + } + currentActionType = typeName; + group.clear(); + if (typeName.equals("IN")) { + members.add(action.name()); + } + if (typeName.equals("OUT")) { + members.remove(action.name()); + } + group.add(action); + } + + if (currentActionType.equals("BILL")) { + actionsResponse.add(ActionsResponse.of(group, members)); + } else { + actionsResponse.add(ActionsResponse.of(group, null)); + } + + return new StepResponse(actionsResponse); + } + + private static ActionAppResponse getFirstAction(List<ActionAppResponse> actions) { + return actions.get(0); + } +} diff --git a/server/src/test/java/server/haengdong/application/EventServiceTest.java b/server/src/test/java/server/haengdong/application/EventServiceTest.java index 31b1c650e..5a3e8bce3 100644 --- a/server/src/test/java/server/haengdong/application/EventServiceTest.java +++ b/server/src/test/java/server/haengdong/application/EventServiceTest.java @@ -2,8 +2,10 @@ import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; import static org.mockito.BDDMockito.given; +import java.util.List; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -11,8 +13,16 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.response.ActionAppResponse; import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.ActionRepository; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.action.MemberActionStatus; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.domain.event.EventTokenProvider; @@ -29,8 +39,20 @@ class EventServiceTest { @Autowired private EventRepository eventRepository; + @Autowired + private ActionRepository actionRepository; + + @Autowired + private BillActionRepository billActionRepository; + + @Autowired + private MemberActionRepository memberActionRepository; + @AfterEach void tearDown() { + billActionRepository.deleteAllInBatch(); + memberActionRepository.deleteAllInBatch(); + actionRepository.deleteAllInBatch(); eventRepository.deleteAllInBatch(); } @@ -56,4 +78,33 @@ void findEventTest() { assertThat(eventDetailAppResponse.eventName()).isEqualTo("행동대장 회식"); } + + @DisplayName("행사에 속한 모든 액션을 조회한다.") + @Test + void findActionsTest() { + Event event = new Event("행동대장 회식", "웨디_토큰"); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + Action action1 = new Action(event, 2L); + MemberAction memberAction1 = new MemberAction(action1, "쿠키", MemberActionStatus.IN, 1L); + Action action2 = new Action(event, 3L); + BillAction billAction = new BillAction(action2, "뽕나무쟁이족발", 30000L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of(memberAction, memberAction1)); + billActionRepository.save(billAction); + + List<ActionAppResponse> actionAppResponses = eventService.findActions("웨디_토큰"); + + assertThat(actionAppResponses).hasSize(3) + .extracting(ActionAppResponse::actionId, + ActionAppResponse::name, + ActionAppResponse::price, + ActionAppResponse::sequence, + ActionAppResponse::actionTypeName) + .containsExactly( + tuple(1L, "토다리", null, 1L, "IN"), + tuple(2L, "쿠키", null, 2L, "IN"), + tuple(3L, "뽕나무쟁이족발", 30000L, 3L, "BILL") + ); + } } diff --git a/server/src/test/java/server/haengdong/presentation/response/StepResponseTest.java b/server/src/test/java/server/haengdong/presentation/response/StepResponseTest.java new file mode 100644 index 000000000..aac78691c --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/response/StepResponseTest.java @@ -0,0 +1,57 @@ +package server.haengdong.presentation.response; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.ActionAppResponse.ActionType; + +@SpringBootTest +class StepResponseTest { + + @Autowired + private ObjectMapper objectMapper; + + @DisplayName("") + @Test + void test() throws JsonProcessingException { + List<ActionAppResponse> actionAppResponse = new ArrayList<>(); + + // IN actions + ActionAppResponse actionAppResponse1 = new ActionAppResponse(3L, "망쵸", null, 3L, ActionType.IN); + actionAppResponse.add(actionAppResponse1); + ActionAppResponse actionAppResponse2 = new ActionAppResponse(4L, "백호", null, 4L, ActionType.IN); + actionAppResponse.add(actionAppResponse2); + + // BILL step 1 + ActionAppResponse actionAppResponse3 = new ActionAppResponse(1L, "감자탕", 10000L, 1L, ActionType.BILL); + actionAppResponse.add(actionAppResponse3); + ActionAppResponse actionAppResponse4 = new ActionAppResponse(2L, "인생네컷", 10000L, 2L, ActionType.BILL); + actionAppResponse.add(actionAppResponse4); + + // IN actions + ActionAppResponse actionAppResponse5 = new ActionAppResponse(5L, "소하", null, 5L, ActionType.IN); + actionAppResponse.add(actionAppResponse5); + ActionAppResponse actionAppResponse6 = new ActionAppResponse(6L, "웨디", null, 6L, ActionType.IN); + actionAppResponse.add(actionAppResponse6); + + // OUT actions + ActionAppResponse actionAppResponse7 = new ActionAppResponse(7L, "망쵸", null, 7L, ActionType.OUT); + actionAppResponse.add(actionAppResponse7); + ActionAppResponse actionAppResponse8 = new ActionAppResponse(8L, "백호", null, 8L, ActionType.OUT); + actionAppResponse.add(actionAppResponse8); + + // BILL step 2 + ActionAppResponse actionAppResponse9 = new ActionAppResponse(9L, "노래방", 20000L, 10L, ActionType.BILL); + actionAppResponse.add(actionAppResponse9); + + // StepResponse creation + StepResponse stepResponse = StepResponse.of(actionAppResponse); + System.out.println("stepResponse = " + stepResponse); + } +} From 74de2a68ea29560f781a195eb1b2ebe4800071a9 Mon Sep 17 00:00:00 2001 From: TaehunLee <85233397+Todari@users.noreply.github.com> Date: Thu, 25 Jul 2024 18:06:07 +0900 Subject: [PATCH 089/178] =?UTF-8?q?chore:=20frontend=20yml=20lint=20?= =?UTF-8?q?=EA=B3=BC=EC=A0=95=20=EC=88=98=EC=A0=95=20(#120)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/ISSUE_TEMPLATE/bug-template.md | 8 ++++++++ ...frontend-pll-request.yml => frontend-pull-request.yml} | 0 client/package.json | 4 ++-- 3 files changed, 10 insertions(+), 2 deletions(-) rename .github/workflows/{frontend-pll-request.yml => frontend-pull-request.yml} (100%) diff --git a/.github/ISSUE_TEMPLATE/bug-template.md b/.github/ISSUE_TEMPLATE/bug-template.md index e14ce93b3..4fab11f91 100644 --- a/.github/ISSUE_TEMPLATE/bug-template.md +++ b/.github/ISSUE_TEMPLATE/bug-template.md @@ -12,6 +12,14 @@ assignees: '' ## 🚨 버그 발생 상황 최대한 상세하게 작성해주세요. +### as-is + +현재 상황에 대해서 알려주세요. + +### to-be + +구현이 된 후 상황을 예상해 주세요. + ## 예상 결과 예상했던 정상적인 결과가 어떤 것인지 설명해주세요. diff --git a/.github/workflows/frontend-pll-request.yml b/.github/workflows/frontend-pull-request.yml similarity index 100% rename from .github/workflows/frontend-pll-request.yml rename to .github/workflows/frontend-pull-request.yml diff --git a/client/package.json b/client/package.json index fed2f5249..3c66313b4 100644 --- a/client/package.json +++ b/client/package.json @@ -6,7 +6,7 @@ "scripts": { "start": "webpack serve ", "build": "webpack --mode production", - "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}' --fix", + "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'", "format": "prettier --write 'src/**/*.{js,jsx,ts,tsx,json,css,scss,md}'" }, "keywords": [], @@ -56,4 +56,4 @@ "npm": ">=10.7.0", "node": ">=20.15.1" } -} +} \ No newline at end of file From b9870edba09577c9d880c6ac32d04a92f90a84fb Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Thu, 25 Jul 2024 18:24:30 +0900 Subject: [PATCH 090/178] =?UTF-8?q?fix:=20=EC=95=A1=EC=85=98=20=EC=9D=B4?= =?UTF-8?q?=EB=A0=A5=EC=9D=B4=20=EC=97=86=EB=8A=94=20=EA=B2=BD=EC=9A=B0=20?= =?UTF-8?q?=EB=B9=88=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EB=B0=98=ED=99=98=20?= =?UTF-8?q?(#122)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/haengdong/presentation/response/StepResponse.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server/src/main/java/server/haengdong/presentation/response/StepResponse.java b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java index 76f92ad53..354f019df 100644 --- a/server/src/main/java/server/haengdong/presentation/response/StepResponse.java +++ b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java @@ -11,6 +11,9 @@ public record StepResponse( ) { public static StepResponse of(List<ActionAppResponse> actions) { + if (actions.isEmpty()) { + return new StepResponse(List.of()); + } List<ActionsResponse> actionsResponse = new ArrayList<>(); Set<String> members = new HashSet<>(); ActionAppResponse firstAction = getFirstAction(actions); From ff2632dccbfa63a980cc3cdb1bb98854e055278d Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Thu, 25 Jul 2024 19:08:42 +0900 Subject: [PATCH 091/178] =?UTF-8?q?=08fix:=20=EC=95=A1=EC=85=98=20?= =?UTF-8?q?=EC=9D=B4=EB=A0=A5=20=EC=A1=B0=ED=9A=8C=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#124)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: HaengdongException 적용 안된 부분 적용 * fix: Transactional 추가 및 StepResponse 로직 수정 --- .../java/server/haengdong/application/EventService.java | 6 +++++- .../server/haengdong/domain/action/MemberActionStatus.java | 5 ++++- .../haengdong/presentation/response/StepResponse.java | 4 ---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java index 94c9dbda1..9ad502606 100644 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -5,6 +5,7 @@ import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import server.haengdong.application.request.EventAppRequest; import server.haengdong.application.response.ActionAppResponse; import server.haengdong.application.response.EventAppResponse; @@ -20,6 +21,7 @@ import server.haengdong.exception.HaengdongException; @RequiredArgsConstructor +@Transactional(readOnly = true) @Service public class EventService { @@ -28,6 +30,7 @@ public class EventService { private final BillActionRepository billActionRepository; private final MemberActionRepository memberActionRepository; + @Transactional public EventAppResponse saveEvent(EventAppRequest request) { String token = eventTokenProvider.createToken(); Event event = request.toEvent(token); @@ -44,7 +47,8 @@ public EventDetailAppResponse findEvent(String token) { } public List<ActionAppResponse> findActions(String token) { - Event event = eventRepository.findByToken(token).orElseThrow(() -> new IllegalArgumentException("")); + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); List<BillAction> billActions = billActionRepository.findByAction_Event(event).stream() .sorted(Comparator.comparing(BillAction::getSequence)).toList(); diff --git a/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java b/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java index afcb31337..0a20817fd 100644 --- a/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java +++ b/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java @@ -1,6 +1,8 @@ package server.haengdong.domain.action; import java.util.Arrays; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; public enum MemberActionStatus { IN, @@ -11,6 +13,7 @@ public static MemberActionStatus of(String status) { return Arrays.stream(MemberActionStatus.values()) .filter(s -> s.name().equals(status)) .findFirst() - .orElseThrow(() -> new IllegalArgumentException("Invalid status: " + status)); + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BAD_REQUEST, + "존재하지 않는 인원 변동 액션입니다.")); } } diff --git a/server/src/main/java/server/haengdong/presentation/response/StepResponse.java b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java index 354f019df..54b2b06b9 100644 --- a/server/src/main/java/server/haengdong/presentation/response/StepResponse.java +++ b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java @@ -37,8 +37,6 @@ public static StepResponse of(List<ActionAppResponse> actions) { } if (currentActionType.equals("BILL")) { actionsResponse.add(ActionsResponse.of(group, members)); - } else { - actionsResponse.add(ActionsResponse.of(group, Set.of())); } currentActionType = typeName; group.clear(); @@ -53,8 +51,6 @@ public static StepResponse of(List<ActionAppResponse> actions) { if (currentActionType.equals("BILL")) { actionsResponse.add(ActionsResponse.of(group, members)); - } else { - actionsResponse.add(ActionsResponse.of(group, null)); } return new StepResponse(actionsResponse); From 6be91dae0550909ff3eac2c6a625f402cae20a32 Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Thu, 25 Jul 2024 19:24:48 +0900 Subject: [PATCH 092/178] =?UTF-8?q?fix:=20StepResponse=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=88=98=EC=A0=95=20(#126)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../haengdong/presentation/response/StepResponse.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/server/src/main/java/server/haengdong/presentation/response/StepResponse.java b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java index 54b2b06b9..a8f3877ef 100644 --- a/server/src/main/java/server/haengdong/presentation/response/StepResponse.java +++ b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java @@ -35,9 +35,7 @@ public static StepResponse of(List<ActionAppResponse> actions) { group.add(action); continue; } - if (currentActionType.equals("BILL")) { - actionsResponse.add(ActionsResponse.of(group, members)); - } + actionsResponse.add(ActionsResponse.of(group, members)); currentActionType = typeName; group.clear(); if (typeName.equals("IN")) { @@ -48,10 +46,7 @@ public static StepResponse of(List<ActionAppResponse> actions) { } group.add(action); } - - if (currentActionType.equals("BILL")) { - actionsResponse.add(ActionsResponse.of(group, members)); - } + actionsResponse.add(ActionsResponse.of(group, members)); return new StepResponse(actionsResponse); } From 38a28f71be90d376d7b3c818067fbc80a0053b0f Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Fri, 26 Jul 2024 12:58:09 +0900 Subject: [PATCH 093/178] =?UTF-8?q?test:=20Gradle,=20Docker=20=EC=BA=90?= =?UTF-8?q?=EC=8B=B1=EC=9D=84=20=EC=9C=84=ED=95=9C=20Feature/#121=20test?= =?UTF-8?q?=20(#128)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: Github Actions Gradle, Docker Build 캐싱 * refactor: Docker 사용하는 포트 번호 수정 * refactor: Docker 사용하는 포트 번호 수정 * test * after cache * after cache2 --- .github/workflows/backend-pull-request.yml | 14 +++++++++++-- .github/workflows/backend-push.yml | 21 ++++++++++++++----- .../haengdong/HaengdongApplication.java | 2 ++ 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/.github/workflows/backend-pull-request.yml b/.github/workflows/backend-pull-request.yml index 113972929..ba6870a61 100644 --- a/.github/workflows/backend-pull-request.yml +++ b/.github/workflows/backend-pull-request.yml @@ -2,7 +2,7 @@ name: backend-pull-request on: pull_request: - branches: [ "main", "develop" ] + branches: [ "main", "develop", "feature/#121" ] paths: - 'server/**' @@ -18,6 +18,16 @@ jobs: - name: CheckOut uses: actions/checkout@v4 + - name: Gradle Caching + uses: actions/cache@v3 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Set up JDK 17 uses: actions/setup-java@v4 with: @@ -25,7 +35,7 @@ jobs: distribution: 'temurin' - name: Setup Gradle - uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 + uses: gradle/gradle-build-action@v2 - name: Test with Gradle Wrapper run: ./gradlew clean build diff --git a/.github/workflows/backend-push.yml b/.github/workflows/backend-push.yml index a35eaea7b..0a3b3e43f 100644 --- a/.github/workflows/backend-push.yml +++ b/.github/workflows/backend-push.yml @@ -2,7 +2,7 @@ name: backend-push on: push: - branches: [ "main", "develop" ] + branches: [ "main", "develop", "feature/#121" ] paths: - 'server/**' @@ -25,6 +25,16 @@ jobs: token: ${{secrets.CONFIG_SUBMODULE_TOKEN}} submodules: true + - name: Gradle Caching + uses: actions/cache@v3 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Set up JDK 17 uses: actions/setup-java@v4 with: @@ -32,7 +42,7 @@ jobs: distribution: 'temurin' - name: Setup Gradle - uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 + uses: gradle/gradle-build-action@v2 - name: Test with Gradle Wrapper run: ./gradlew test @@ -48,8 +58,9 @@ jobs: - name: Build and push run: | - docker buildx build --platform linux/arm64 -t \ - ${{ secrets.DOCKER_USERNAME }}/haengdong-backend-dev --push . + docker buildx build --platform linux/arm64 --cache-from=type=registry,ref=${{ secrets.DOCKER_USERNAME }}/haengdong-backend-dev:cache \ + --cache-to=type=registry,ref=${{ secrets.DOCKER_USERNAME }}/haengdong-backend-dev:cache,mode=max \ + -t ${{ secrets.DOCKER_USERNAME }}/haengdong-backend-dev --push . deploy: needs: build @@ -68,4 +79,4 @@ jobs: run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/haengdong-backend-dev - name: Docker run - run: sudo docker run -d -p 80:8080 --name haengdong-backend-dev haengdong/haengdong-backend-dev + run: sudo docker run -d -p 8080:8080 --name haengdong-backend-dev haengdong/haengdong-backend-dev diff --git a/server/src/main/java/server/haengdong/HaengdongApplication.java b/server/src/main/java/server/haengdong/HaengdongApplication.java index 31b6e46e7..7549a9784 100644 --- a/server/src/main/java/server/haengdong/HaengdongApplication.java +++ b/server/src/main/java/server/haengdong/HaengdongApplication.java @@ -8,6 +8,8 @@ public class HaengdongApplication { public static void main(String[] args) { SpringApplication.run(HaengdongApplication.class, args); + + } } From 1d2e71a716674d15e9b0a3e19235ee0f1d1d0dc4 Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Fri, 26 Jul 2024 13:12:21 +0900 Subject: [PATCH 094/178] =?UTF-8?q?test:=20Gardle,=20Docker=20=EC=BA=90?= =?UTF-8?q?=EC=8B=B1=EC=9D=84=20=EC=9C=84=ED=95=9C=20Feature/#121=20test2?= =?UTF-8?q?=20(#130)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: Github Actions Gradle, Docker Build 캐싱 * refactor: Docker 사용하는 포트 번호 수정 * refactor: Docker 사용하는 포트 번호 수정 * after cache --- server/src/main/java/server/haengdong/HaengdongApplication.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/server/haengdong/HaengdongApplication.java b/server/src/main/java/server/haengdong/HaengdongApplication.java index 7549a9784..be22f61d0 100644 --- a/server/src/main/java/server/haengdong/HaengdongApplication.java +++ b/server/src/main/java/server/haengdong/HaengdongApplication.java @@ -11,5 +11,5 @@ public static void main(String[] args) { } - + } From 883884427ff87f4325acd2c5cf7e84be57adf291 Mon Sep 17 00:00:00 2001 From: Juhwan Kim <13selfesteem91@naver.com> Date: Fri, 26 Jul 2024 13:44:42 +0900 Subject: [PATCH 095/178] revert: gradle cache, docker cache (#133) --- .github/workflows/backend-pull-request.yml | 14 ++----------- .github/workflows/backend-push.yml | 21 +++++-------------- .../haengdong/HaengdongApplication.java | 4 +--- 3 files changed, 8 insertions(+), 31 deletions(-) diff --git a/.github/workflows/backend-pull-request.yml b/.github/workflows/backend-pull-request.yml index ba6870a61..113972929 100644 --- a/.github/workflows/backend-pull-request.yml +++ b/.github/workflows/backend-pull-request.yml @@ -2,7 +2,7 @@ name: backend-pull-request on: pull_request: - branches: [ "main", "develop", "feature/#121" ] + branches: [ "main", "develop" ] paths: - 'server/**' @@ -18,16 +18,6 @@ jobs: - name: CheckOut uses: actions/checkout@v4 - - name: Gradle Caching - uses: actions/cache@v3 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Set up JDK 17 uses: actions/setup-java@v4 with: @@ -35,7 +25,7 @@ jobs: distribution: 'temurin' - name: Setup Gradle - uses: gradle/gradle-build-action@v2 + uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 - name: Test with Gradle Wrapper run: ./gradlew clean build diff --git a/.github/workflows/backend-push.yml b/.github/workflows/backend-push.yml index 0a3b3e43f..a35eaea7b 100644 --- a/.github/workflows/backend-push.yml +++ b/.github/workflows/backend-push.yml @@ -2,7 +2,7 @@ name: backend-push on: push: - branches: [ "main", "develop", "feature/#121" ] + branches: [ "main", "develop" ] paths: - 'server/**' @@ -25,16 +25,6 @@ jobs: token: ${{secrets.CONFIG_SUBMODULE_TOKEN}} submodules: true - - name: Gradle Caching - uses: actions/cache@v3 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Set up JDK 17 uses: actions/setup-java@v4 with: @@ -42,7 +32,7 @@ jobs: distribution: 'temurin' - name: Setup Gradle - uses: gradle/gradle-build-action@v2 + uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 - name: Test with Gradle Wrapper run: ./gradlew test @@ -58,9 +48,8 @@ jobs: - name: Build and push run: | - docker buildx build --platform linux/arm64 --cache-from=type=registry,ref=${{ secrets.DOCKER_USERNAME }}/haengdong-backend-dev:cache \ - --cache-to=type=registry,ref=${{ secrets.DOCKER_USERNAME }}/haengdong-backend-dev:cache,mode=max \ - -t ${{ secrets.DOCKER_USERNAME }}/haengdong-backend-dev --push . + docker buildx build --platform linux/arm64 -t \ + ${{ secrets.DOCKER_USERNAME }}/haengdong-backend-dev --push . deploy: needs: build @@ -79,4 +68,4 @@ jobs: run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/haengdong-backend-dev - name: Docker run - run: sudo docker run -d -p 8080:8080 --name haengdong-backend-dev haengdong/haengdong-backend-dev + run: sudo docker run -d -p 80:8080 --name haengdong-backend-dev haengdong/haengdong-backend-dev diff --git a/server/src/main/java/server/haengdong/HaengdongApplication.java b/server/src/main/java/server/haengdong/HaengdongApplication.java index be22f61d0..31b6e46e7 100644 --- a/server/src/main/java/server/haengdong/HaengdongApplication.java +++ b/server/src/main/java/server/haengdong/HaengdongApplication.java @@ -8,8 +8,6 @@ public class HaengdongApplication { public static void main(String[] args) { SpringApplication.run(HaengdongApplication.class, args); - - } - + } From b0f0ffa14edda42c7f846b5ff59ba267226f3384 Mon Sep 17 00:00:00 2001 From: Juhwan Kim <13selfesteem91@naver.com> Date: Fri, 26 Jul 2024 13:51:32 +0900 Subject: [PATCH 096/178] =?UTF-8?q?refactor:=20=EC=95=A0=ED=94=8C=EB=A6=AC?= =?UTF-8?q?=EC=BC=80=EC=9D=B4=EC=85=98=20=EB=8F=84=EC=BB=A4=20=ED=8F=AC?= =?UTF-8?q?=ED=8A=B8=20=EB=B2=88=ED=98=B8=20=EC=88=98=EC=A0=95=20(#134)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/backend-push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/backend-push.yml b/.github/workflows/backend-push.yml index a35eaea7b..b22b20aa7 100644 --- a/.github/workflows/backend-push.yml +++ b/.github/workflows/backend-push.yml @@ -68,4 +68,4 @@ jobs: run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/haengdong-backend-dev - name: Docker run - run: sudo docker run -d -p 80:8080 --name haengdong-backend-dev haengdong/haengdong-backend-dev + run: sudo docker run -d -p 8080:8080 --name haengdong-backend-dev haengdong/haengdong-backend-dev From d056d28b0e8e2d4c19466f51088c897ccdf66d6f Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Fri, 26 Jul 2024 13:59:06 +0900 Subject: [PATCH 097/178] =?UTF-8?q?refactor:=20Docker=20=EB=B9=8C=EB=93=9C?= =?UTF-8?q?=20=EC=84=B1=EB=8A=A5=20=EA=B0=9C=EC=84=A0=20(#138)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/backend-push.yml | 2 +- server/Dockerfile | 10 +--------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/.github/workflows/backend-push.yml b/.github/workflows/backend-push.yml index b22b20aa7..be973a6a9 100644 --- a/.github/workflows/backend-push.yml +++ b/.github/workflows/backend-push.yml @@ -35,7 +35,7 @@ jobs: uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 - name: Test with Gradle Wrapper - run: ./gradlew test + run: ./gradlew clean build - name: Login to Docker Hub uses: docker/login-action@v3 diff --git a/server/Dockerfile b/server/Dockerfile index 66a2d0ab3..37e37d237 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -1,16 +1,8 @@ -FROM gradle:7.6.1-jdk17 AS build - -WORKDIR /app - -COPY . /app - -RUN gradle clean build -x test - FROM openjdk:17-jdk-slim WORKDIR /app -COPY --from=build /app/build/libs/*.jar /app/haengdong-0.0.1-SNAPSHOT.jar +COPY /build/libs/*.jar /app/haengdong-0.0.1-SNAPSHOT.jar EXPOSE 8080 ENTRYPOINT ["java"] From 14be9b3d8ec17289ecf78bd1dbb63485334e9b4a Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Fri, 26 Jul 2024 14:58:45 +0900 Subject: [PATCH 098/178] =?UTF-8?q?refactor:=20=EC=B0=B8=EC=97=AC=EC=9E=90?= =?UTF-8?q?=20=EC=A0=95=EC=82=B0=20=ED=98=84=ED=99=A9=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=20=EB=A6=AC=ED=8E=99=ED=86=A0=EB=A7=81=20(#110)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 참여자 정산 현황 로직 수정 * refactor: forEach -> stream 변경 --- .../haengdong/application/ActionService.java | 13 +++---- .../domain/action/CurrentMembers.java | 39 ++++++++++++++++--- .../haengdong/domain/action/MemberAction.java | 4 ++ ...BillReports.java => MemberBillReport.java} | 36 +++++++---------- .../domain/action/CurrentMembersTest.java | 28 +++++++++++++ ...rtsTest.java => MemberBillReportTest.java} | 6 +-- 6 files changed, 88 insertions(+), 38 deletions(-) rename server/src/main/java/server/haengdong/domain/action/{MemberBillReports.java => MemberBillReport.java} (66%) rename server/src/test/java/server/haengdong/domain/action/{MemberBillReportsTest.java => MemberBillReportTest.java} (89%) diff --git a/server/src/main/java/server/haengdong/application/ActionService.java b/server/src/main/java/server/haengdong/application/ActionService.java index b28374bb9..bda638756 100644 --- a/server/src/main/java/server/haengdong/application/ActionService.java +++ b/server/src/main/java/server/haengdong/application/ActionService.java @@ -1,6 +1,5 @@ package server.haengdong.application; -import java.util.ArrayList; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -9,7 +8,7 @@ import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionRepository; -import server.haengdong.domain.action.MemberBillReports; +import server.haengdong.domain.action.MemberBillReport; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.exception.HaengdongErrorCode; @@ -29,12 +28,10 @@ public List<MemberBillReportAppResponse> getMemberBillReports(String token) { List<BillAction> billActions = billActionRepository.findByAction_Event(event); List<MemberAction> memberActions = memberActionRepository.findAllByEvent(event); - MemberBillReports memberBillReports = MemberBillReports.createByActions(billActions, memberActions); + MemberBillReport memberBillReport = MemberBillReport.createByActions(billActions, memberActions); - List<MemberBillReportAppResponse> memberBillReportResponses = new ArrayList<>(); - memberBillReports.getReports().forEach( - (member, price) -> memberBillReportResponses.add(new MemberBillReportAppResponse(member, price)) - ); - return memberBillReportResponses; + return memberBillReport.getReports().entrySet().stream() + .map(entry -> new MemberBillReportAppResponse(entry.getKey(), entry.getValue())) + .toList(); } } diff --git a/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java b/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java index e6843a404..298a8a965 100644 --- a/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java +++ b/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java @@ -1,19 +1,23 @@ package server.haengdong.domain.action; +import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -@Getter -@RequiredArgsConstructor(access = AccessLevel.PRIVATE) public class CurrentMembers { private final Set<String> members; + public CurrentMembers() { + this(new HashSet<>()); + } + + private CurrentMembers(Set<String> members) { + this.members = members; + } + public static CurrentMembers of(List<MemberAction> memberActions) { List<MemberAction> sortedMemberActions = getSortedMemberActions(memberActions); Set<String> members = new HashSet<>(); @@ -34,4 +38,29 @@ private static List<MemberAction> getSortedMemberActions(List<MemberAction> memb .sorted(Comparator.comparing(MemberAction::getSequence)) .toList(); } + + public CurrentMembers addMemberAction(MemberAction memberAction) { + String memberName = memberAction.getMemberName(); + + Set<String> currentMembers = new HashSet<>(members); + + if (memberAction.isIn()) { + currentMembers.add(memberName); + } else { + currentMembers.remove(memberName); + } + return new CurrentMembers(currentMembers); + } + + public boolean isEmpty() { + return members.isEmpty(); + } + + public int size() { + return members.size(); + } + + public Set<String> getMembers() { + return Collections.unmodifiableSet(members); + } } diff --git a/server/src/main/java/server/haengdong/domain/action/MemberAction.java b/server/src/main/java/server/haengdong/domain/action/MemberAction.java index af340de3f..67387cbde 100644 --- a/server/src/main/java/server/haengdong/domain/action/MemberAction.java +++ b/server/src/main/java/server/haengdong/domain/action/MemberAction.java @@ -43,6 +43,10 @@ public boolean isSameName(String name) { return memberName.equals(name); } + public boolean isIn() { + return status == MemberActionStatus.IN; + } + public boolean isSameStatus(MemberActionStatus memberActionStatus) { return status == memberActionStatus; } diff --git a/server/src/main/java/server/haengdong/domain/action/MemberBillReports.java b/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java similarity index 66% rename from server/src/main/java/server/haengdong/domain/action/MemberBillReports.java rename to server/src/main/java/server/haengdong/domain/action/MemberBillReport.java index aa928d2e4..dbf2b49ac 100644 --- a/server/src/main/java/server/haengdong/domain/action/MemberBillReports.java +++ b/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java @@ -2,33 +2,31 @@ import static java.util.stream.Collectors.toMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.PriorityQueue; -import java.util.Set; import java.util.function.Function; import lombok.Getter; @Getter -public class MemberBillReports { +public class MemberBillReport { private final Map<String, Long> reports; - private MemberBillReports(Map<String, Long> reports) { + private MemberBillReport(Map<String, Long> reports) { this.reports = reports; } - public static MemberBillReports createByActions(List<BillAction> billActions, List<MemberAction> memberActions) { + public static MemberBillReport createByActions(List<BillAction> billActions, List<MemberAction> memberActions) { PriorityQueue<BillAction> sortedBillActions = new PriorityQueue<>(billActions); PriorityQueue<MemberAction> sortedMemberActions = new PriorityQueue<>(memberActions); Map<String, Long> memberBillReports = initReports(memberActions); - Set<String> currentMembers = new HashSet<>(); - + CurrentMembers currentMembers = new CurrentMembers(); while (!sortedBillActions.isEmpty() && !sortedMemberActions.isEmpty()) { if (isMemberActionTurn(sortedMemberActions, sortedBillActions)) { - addMemberAction(sortedMemberActions, currentMembers); + MemberAction memberAction = sortedMemberActions.poll(); + currentMembers = currentMembers.addMemberAction(memberAction); continue; } addBillAction(sortedBillActions, currentMembers, memberBillReports); @@ -38,7 +36,7 @@ public static MemberBillReports createByActions(List<BillAction> billActions, Li addBillAction(sortedBillActions, currentMembers, memberBillReports); } - return new MemberBillReports(memberBillReports); + return new MemberBillReport(memberBillReports); } private static Map<String, Long> initReports(List<MemberAction> memberActions) { @@ -58,25 +56,19 @@ private static boolean isMemberActionTurn( return memberAction.getSequence() < billAction.getSequence(); } - private static void addMemberAction(PriorityQueue<MemberAction> sortedMemberActions, Set<String> currentMembers) { - MemberAction memberAction = sortedMemberActions.poll(); - String memberName = memberAction.getMemberName(); - if (memberAction.isSameStatus(MemberActionStatus.IN)) { - currentMembers.add(memberName); - return; - } - currentMembers.remove(memberAction.getMemberName()); - } - private static void addBillAction( PriorityQueue<BillAction> sortedBillActions, - Set<String> currentMembers, + CurrentMembers currentMembers, Map<String, Long> memberBillReports ) { BillAction billAction = sortedBillActions.poll(); + if (currentMembers.isEmpty()) { + return; + } + Long pricePerMember = billAction.getPrice() / currentMembers.size(); - for (String currentMember : currentMembers) { - Long price = memberBillReports.getOrDefault(currentMember, 0L) + pricePerMember; + for (String currentMember : currentMembers.getMembers()) { + Long price = memberBillReports.get(currentMember) + pricePerMember; memberBillReports.put(currentMember, price); } } diff --git a/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java b/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java index 37ddca432..389ca70c1 100644 --- a/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java +++ b/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java @@ -5,6 +5,7 @@ import static server.haengdong.domain.action.MemberActionStatus.OUT; import java.util.List; +import java.util.Set; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import server.haengdong.domain.event.Event; @@ -27,4 +28,31 @@ void of() { assertThat(currentMembers.getMembers()) .containsExactlyInAnyOrder("망쵸", "웨디"); } + + @DisplayName("인원 변동 액션의 상태가 IN이면 현재 인원에 추가한다.") + @Test + void addMemberAction1() { + CurrentMembers currentMembers = new CurrentMembers(); + Event event = new Event("이벤트", "token"); + MemberAction memberAction = new MemberAction(new Action(event, 1L), "웨디", IN, 1L); + + CurrentMembers addedCurrentMembers = currentMembers.addMemberAction(memberAction); + Set<String> members = addedCurrentMembers.getMembers(); + + assertThat(members).hasSize(1) + .containsExactly("웨디"); + } + + @DisplayName("인원 변동 액션의 상태가 OUT이면 현재 인원에서 제외한다.") + @Test + void addMemberAction2() { + Event event = new Event("이벤트", "token"); + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "웨디", IN, 1L); + CurrentMembers currentMembers = new CurrentMembers().addMemberAction(memberAction1); + MemberAction memberAction2 = new MemberAction(new Action(event, 1L), "웨디", OUT, 1L); + + CurrentMembers addedCurrentMembers = currentMembers.addMemberAction(memberAction2); + + assertThat(addedCurrentMembers.getMembers()).hasSize(0); + } } diff --git a/server/src/test/java/server/haengdong/domain/action/MemberBillReportsTest.java b/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java similarity index 89% rename from server/src/test/java/server/haengdong/domain/action/MemberBillReportsTest.java rename to server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java index db0e2ff37..9ad27d5bc 100644 --- a/server/src/test/java/server/haengdong/domain/action/MemberBillReportsTest.java +++ b/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java @@ -10,7 +10,7 @@ import org.junit.jupiter.api.Test; import server.haengdong.domain.event.Event; -class MemberBillReportsTest { +class MemberBillReportTest { @DisplayName("액션 목록으로 참가자 정산 리포트를 생성한다.") @Test @@ -29,9 +29,9 @@ void createByActions() { new MemberAction(new Action(event, 5L), "감자", OUT, 2L) ); - MemberBillReports memberBillReports = MemberBillReports.createByActions(billActions, memberActions); + MemberBillReport memberBillReport = MemberBillReport.createByActions(billActions, memberActions); - assertThat(memberBillReports.getReports()) + assertThat(memberBillReport.getReports()) .containsAllEntriesOf( Map.of( "감자", 20_000L, From 897746625bdaca74850137c765041ff4c7da4858 Mon Sep 17 00:00:00 2001 From: TaehunLee <85233397+Todari@users.noreply.github.com> Date: Sat, 27 Jul 2024 22:03:58 +0900 Subject: [PATCH 099/178] =?UTF-8?q?chore:=20storybook=20chromatic=20?= =?UTF-8?q?=EB=B0=B0=ED=8F=AC=20(#81)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: storybook chromatic workfloe * style: EOL 제거 * chore: storybook 배포를 위한 workflow 설정 * chore: storybook 배포를 위한 workflow 설정 * chore: workflow node 설정 추가 * chore: lint flow path 변경 * chore: run lint 수정 * chore: eslint-config-prettier 추가 * chore: lint 적용 * chore: airbnb 제거 * chore: eslint 설정 수정 * chore: chromatic working directory 변경 --- .github/workflows/design-pull-request.yml | 61 +++ HDesign/eslint.config.mjs | 49 ++- HDesign/package-lock.json | 355 ++++++++---------- HDesign/package.json | 4 +- .../src/components/BillItem/BillItem.style.ts | 3 +- HDesign/src/components/BillItem/BillItem.tsx | 10 +- .../DragHandleItem/DragHandleItem.style.ts | 3 +- .../DragHandleItem/DragHandleItem.tsx | 12 +- .../ExpenseList/ExpenseList.style.ts | 3 +- .../components/ExpenseList/ExpenseList.tsx | 12 +- HDesign/src/components/Flex/Flex.tsx | 8 +- .../src/components/IconButton/IconButton.tsx | 1 - .../components/InOutItem/InOutItem.style.ts | 3 +- .../src/components/InOutItem/InOutItem.tsx | 8 +- HDesign/src/components/Input/Input.style.ts | 1 + .../src/components/Search/Search.stories.tsx | 5 +- HDesign/src/components/Search/Search.style.ts | 3 +- HDesign/src/components/Search/Search.tsx | 10 +- .../src/components/StepItem/StepItem.style.ts | 3 +- HDesign/src/components/StepItem/StepItem.tsx | 6 +- HDesign/src/components/Switch/Switch.tsx | 5 +- HDesign/src/components/Tab/Tab.stories.tsx | 3 +- HDesign/src/components/Tab/Tab.style.ts | 3 +- HDesign/src/components/Tab/Tab.tsx | 3 +- .../components/TextButton/TextButton.style.ts | 4 +- .../src/components/TextButton/TextButton.tsx | 7 +- .../src/components/TopNav/TopNav.stories.ts | 1 + HDesign/src/components/TopNav/TopNav.tsx | 10 +- HDesign/src/layouts/MainLayout.tsx | 5 +- 29 files changed, 339 insertions(+), 262 deletions(-) create mode 100644 .github/workflows/design-pull-request.yml diff --git a/.github/workflows/design-pull-request.yml b/.github/workflows/design-pull-request.yml new file mode 100644 index 000000000..4d54e8b39 --- /dev/null +++ b/.github/workflows/design-pull-request.yml @@ -0,0 +1,61 @@ +name: Storybook Deployment +run-name: ${{ github.actor }}의 스토리북 배포 +on: + pull_request: + branches: + - develop + paths: + - 'HDesign/**' + +jobs: + storybook: + runs-on: ubuntu-latest + outputs: + status: ${{ job.status }} + + defaults: + run: + shell: bash + working-directory: ./HDesign + + steps: + - name: checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: cache dependencies + id: cache + uses: actions/cache@v3 + with: + path: "**/node_modules" + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}-storybook + + - name: Set up Node.js + uses: actions/setup-node@v2 + with: + node-version: '20.15.1' + + - name: depedency install + if: steps.cache.outputs.cache-hit != 'true' + run: npm ci + + - name: run lint + working-directory: ./HDesign + run: npm run lint + + - name: publish to chromatic + working-directory: ./HDesign + id: chromatic + uses: chromaui/action@v1 + with: + projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} + token: ${{ secrets.GITHUB_TOKEN }} + + - name: comment PR + uses: thollander/actions-comment-pull-request@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + message: "🚀storybook: ${{ steps.chromatic.outputs.storybookUrl }}" + \ No newline at end of file diff --git a/HDesign/eslint.config.mjs b/HDesign/eslint.config.mjs index b6040f04e..96b3da00a 100644 --- a/HDesign/eslint.config.mjs +++ b/HDesign/eslint.config.mjs @@ -21,8 +21,6 @@ const compat = new FlatCompat({ export default [ ...fixupConfigRules( compat.extends( - 'airbnb', - 'airbnb/hooks', 'eslint:recommended', 'plugin:react/recommended', 'plugin:@typescript-eslint/recommended', @@ -64,12 +62,38 @@ export default [ }, rules: { + 'no-use-before-define': 0, 'prettier/prettier': 'error', 'react/react-in-jsx-scope': 'off', 'react/prop-types': 'off', - 'react/jsx-uses-vars': 'error', - '@typescript-eslint/no-use-before-define': ['error'], - '@typescript-eslint/explicit-module-boundary-types': 'error', + 'import/prefer-default-export': 0, + 'import/no-named-as-default': 0, + 'import/namespace': 0, + 'import/extensions': 0, + 'import/no-cycle': 0, + 'react/no-unknown-property': 0, + 'react/jsx-filename-extension': [1, {extensions: ['.ts', '.tsx']}], + 'react/function-component-definition': 0, + 'react/jsx-props-no-spreading': 0, + 'react/jsx-key': 0, + 'react/button-has-type': 'off', + 'no-shadow': 0, + 'no-console': 0, + 'no-alert': 0, + 'react/no-children-prop': 'off', + 'react/no-array-index-key': 'off', + 'react-hooks/exhaustive-deps': 'off', + 'react-hooks/rules-of-hooks': 'off', + 'react/jsx-no-useless-fragment': 'off', + 'react/jsx-no-constructed-context-values': 'off', + 'jsx-a11y/click-events-have-key-events': 'off', + 'jsx-a11y/no-static-element-interactions': 'off', + + '@typescript-eslint/no-unused-vars': 0, + + // 'react/jsx-uses-vars': 'error', + // '@typescript-eslint/no-use-before-define': ['error'], + // '@typescript-eslint/explicit-module-boundary-types': 'error', 'import/order': [ 'error', @@ -89,6 +113,11 @@ export default [ group: 'internal', position: 'after', }, + { + pattern: '@layouts/*', + group: 'internal', + position: 'after', + }, { pattern: '@assets/*', group: 'internal', @@ -104,6 +133,16 @@ export default [ group: 'internal', position: 'after', }, + { + pattern: '@types/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@utils/*', + group: 'internal', + position: 'after', + }, ], }, ], diff --git a/HDesign/package-lock.json b/HDesign/package-lock.json index 9a18cd5ff..d6b1de8f4 100644 --- a/HDesign/package-lock.json +++ b/HDesign/package-lock.json @@ -32,8 +32,8 @@ "@types/react-dom": "^18.3.0", "@typescript-eslint/eslint-plugin": "^7.16.0", "@typescript-eslint/parser": "^7.16.0", - "eslint": "^8.57.0", - "eslint-config-airbnb": "^19.0.4", + "eslint": "^9.7.0", + "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.29.1", "eslint-plugin-jsx-a11y": "^6.9.0", @@ -2723,30 +2723,21 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "node_modules/@eslint/config-array": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", + "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", "dev": true, "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "node_modules/@eslint/config-array/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", @@ -2756,7 +2747,7 @@ "concat-map": "0.0.1" } }, - "node_modules/@eslint/eslintrc/node_modules/debug": { + "node_modules/@eslint/config-array/node_modules/debug": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", @@ -2773,22 +2764,7 @@ } } }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "node_modules/@eslint/config-array/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", @@ -2800,49 +2776,36 @@ "node": "*" } }, - "node_modules/@eslint/eslintrc/node_modules/ms": { + "node_modules/@eslint/config-array/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dev": true, - "engines": { - "node": ">=10" + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "9.7.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.7.0.tgz", - "integrity": "sha512-ChuWDQenef8OSFnvuxv0TCVxEwmu3+hPNKvM9B34qpM0rDRbjL8t5QkQeHHeAfsKQjuH9wS82WeCi1J/owatng==", - "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" }, - "engines": { - "node": ">=10.10.0" + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", @@ -2852,7 +2815,7 @@ "concat-map": "0.0.1" } }, - "node_modules/@humanwhocodes/config-array/node_modules/debug": { + "node_modules/@eslint/eslintrc/node_modules/debug": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", @@ -2869,7 +2832,19 @@ } } }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", @@ -2881,12 +2856,30 @@ "node": "*" } }, - "node_modules/@humanwhocodes/config-array/node_modules/ms": { + "node_modules/@eslint/eslintrc/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/@eslint/js": { + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.7.0.tgz", + "integrity": "sha512-ChuWDQenef8OSFnvuxv0TCVxEwmu3+hPNKvM9B34qpM0rDRbjL8t5QkQeHHeAfsKQjuH9wS82WeCi1J/owatng==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -2900,12 +2893,18 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@jest/schemas": { "version": "29.6.3", @@ -6684,12 +6683,6 @@ "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==", "dev": true }, - "node_modules/confusing-browser-globals": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", - "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", - "dev": true - }, "node_modules/consola": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", @@ -7691,41 +7684,37 @@ } }, "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.7.0.tgz", + "integrity": "sha512-FzJ9D/0nGiCGBf8UXO/IGLTgLVzIxze1zpfA8Ton2mjLovXdAPlYDv+MQDcqj3TmrhAGYfOpz9RfR+ent0AgAw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.17.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.7.0", "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", - "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.4.2", + "eslint-scope": "^8.0.2", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "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", @@ -7739,59 +7728,22 @@ "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-airbnb": { - "version": "19.0.4", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz", - "integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==", - "dev": true, - "dependencies": { - "eslint-config-airbnb-base": "^15.0.0", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5" - }, - "engines": { - "node": "^10.12.0 || ^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.3", - "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.28.0", - "eslint-plugin-react-hooks": "^4.3.0" + "url": "https://eslint.org/donate" } }, - "node_modules/eslint-config-airbnb-base": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", - "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", "dev": true, - "dependencies": { - "confusing-browser-globals": "^1.0.10", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5", - "semver": "^6.3.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" + "bin": { + "eslint-config-prettier": "bin/cli.js" }, "peerDependencies": { - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.2" - } - }, - "node_modules/eslint-config-airbnb-base/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "eslint": ">=7.0.0" } }, "node_modules/eslint-import-resolver-node": { @@ -8237,15 +8189,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -8273,18 +8216,6 @@ } } }, - "node_modules/eslint/node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/eslint/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -8298,16 +8229,28 @@ } }, "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", + "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -8350,21 +8293,6 @@ "node": ">=10.13.0" } }, - "node_modules/eslint/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -8428,30 +8356,30 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "node_modules/espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", "dev": true, + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint" } }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -8692,15 +8620,28 @@ } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" + } + }, + "node_modules/file-entry-cache/node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" } }, "node_modules/file-loader": { diff --git a/HDesign/package.json b/HDesign/package.json index 42f857a3e..b077aa3ba 100644 --- a/HDesign/package.json +++ b/HDesign/package.json @@ -36,8 +36,8 @@ "@types/react-dom": "^18.3.0", "@typescript-eslint/eslint-plugin": "^7.16.0", "@typescript-eslint/parser": "^7.16.0", - "eslint": "^8.57.0", - "eslint-config-airbnb": "^19.0.4", + "eslint": "^9.7.0", + "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.29.1", "eslint-plugin-jsx-a11y": "^6.9.0", diff --git a/HDesign/src/components/BillItem/BillItem.style.ts b/HDesign/src/components/BillItem/BillItem.style.ts index dceb9af92..54531e095 100644 --- a/HDesign/src/components/BillItem/BillItem.style.ts +++ b/HDesign/src/components/BillItem/BillItem.style.ts @@ -1,6 +1,7 @@ -import {Theme} from '@/theme/theme.type'; import {css} from '@emotion/react'; +import {Theme} from '@/theme/theme.type'; + export const textStyle = (theme: Theme) => css({ color: theme.colors.black, diff --git a/HDesign/src/components/BillItem/BillItem.tsx b/HDesign/src/components/BillItem/BillItem.tsx index 0823d8add..bf5d916cd 100644 --- a/HDesign/src/components/BillItem/BillItem.tsx +++ b/HDesign/src/components/BillItem/BillItem.tsx @@ -1,12 +1,16 @@ /** @jsxImportSource @emotion/react */ import React from 'react'; -import {useTheme} from '@theme/HDesignProvider'; -import {BillItemProps} from './BillItem.type'; -import {textStyle} from './BillItem.style'; + import Text from '@components/Text/Text'; + +import {useTheme} from '@theme/HDesignProvider'; + import DragHandleItem from '../DragHandleItem/DragHandleItem'; import Flex from '../Flex/Flex'; +import {BillItemProps} from './BillItem.type'; +import {textStyle} from './BillItem.style'; + export const BillItem: React.FC<BillItemProps> = ({ name = '', price = 0, diff --git a/HDesign/src/components/DragHandleItem/DragHandleItem.style.ts b/HDesign/src/components/DragHandleItem/DragHandleItem.style.ts index a08dfc574..972050619 100644 --- a/HDesign/src/components/DragHandleItem/DragHandleItem.style.ts +++ b/HDesign/src/components/DragHandleItem/DragHandleItem.style.ts @@ -1,6 +1,7 @@ +import {css} from '@emotion/react'; + import {Theme} from '@/theme/theme.type'; import {ColorKeys} from '@/token/colors'; -import {css} from '@emotion/react'; export const dragHandleItemStyle = (theme: Theme, hasDragHandle: boolean, backgroundColor: ColorKeys) => css({ diff --git a/HDesign/src/components/DragHandleItem/DragHandleItem.tsx b/HDesign/src/components/DragHandleItem/DragHandleItem.tsx index 8ae6aeb8c..9c92a6c8f 100644 --- a/HDesign/src/components/DragHandleItem/DragHandleItem.tsx +++ b/HDesign/src/components/DragHandleItem/DragHandleItem.tsx @@ -1,12 +1,14 @@ /** @jsxImportSource @emotion/react */ import React from 'react'; +import {StrictPropsWithChildren} from '@/types/strictPropsWithChildren'; +import {COLORS, ColorKeys} from '@/token/colors'; + import {useTheme} from '@theme/HDesignProvider'; import IconButton from '../IconButton/IconButton'; -import {StrictPropsWithChildren} from '@/types/strictPropsWithChildren'; + import {dragHandleItemStyle, prefixStyle} from './DragHandleItem.style'; -import {COLORS, ColorKeys} from '@/token/colors'; interface DragHandleItemCustomProps { hasDragHandle?: boolean; @@ -15,12 +17,12 @@ interface DragHandleItemCustomProps { export type DragHandleItemProps = React.ComponentProps<'div'> & DragHandleItemCustomProps; -export const DragHandleItem = ({ +export function DragHandleItem({ hasDragHandle = false, backgroundColor = 'white', children, ...htmlProps -}: StrictPropsWithChildren<DragHandleItemProps>) => { +}: StrictPropsWithChildren<DragHandleItemProps>) { const {theme} = useTheme(); // TODO: (@toari) : 사람 수 많을 때 UX writing 처리 @@ -32,5 +34,5 @@ export const DragHandleItem = ({ </div> </div> ); -}; +} export default DragHandleItem; diff --git a/HDesign/src/components/ExpenseList/ExpenseList.style.ts b/HDesign/src/components/ExpenseList/ExpenseList.style.ts index 30d71de79..58c8ba7f5 100644 --- a/HDesign/src/components/ExpenseList/ExpenseList.style.ts +++ b/HDesign/src/components/ExpenseList/ExpenseList.style.ts @@ -1,6 +1,7 @@ -import {Theme} from '@/theme/theme.type'; import {css} from '@emotion/react'; +import {Theme} from '@/theme/theme.type'; + export const expenseItemStyle = () => css({ display: 'flex', diff --git a/HDesign/src/components/ExpenseList/ExpenseList.tsx b/HDesign/src/components/ExpenseList/ExpenseList.tsx index 0c1b8a771..8dbc71858 100644 --- a/HDesign/src/components/ExpenseList/ExpenseList.tsx +++ b/HDesign/src/components/ExpenseList/ExpenseList.tsx @@ -1,14 +1,16 @@ /** @jsxImportSource @emotion/react */ -import {useTheme} from '@theme/HDesignProvider'; import Text from '@components/Text/Text'; + import {Arrow} from '@assets/index'; +import {useTheme} from '@theme/HDesignProvider'; + import {ExpenseItemProps, ExpenseListProps} from './ExpenseList.type'; import {expenseItemStyle, expenseListStyle, expenseItemLeftStyle, TextStyle} from './ExpenseList.style'; // TODO: (@soha) 따로 파일 분리할까 고민중.. 여기서만 사용할 것 같긴 한데.. 흠 -const ExpenseItem = ({name, price}: ExpenseItemProps) => { +function ExpenseItem({name, price}: ExpenseItemProps) { const {theme} = useTheme(); return ( <button css={expenseItemStyle}> @@ -21,9 +23,9 @@ const ExpenseItem = ({name, price}: ExpenseItemProps) => { </div> </button> ); -}; +} -const ExpenseList = ({expenseList = []}: ExpenseListProps) => { +function ExpenseList({expenseList = []}: ExpenseListProps) { const {theme} = useTheme(); return ( <div css={expenseListStyle(theme)}> @@ -32,6 +34,6 @@ const ExpenseList = ({expenseList = []}: ExpenseListProps) => { ))} </div> ); -}; +} export default ExpenseList; diff --git a/HDesign/src/components/Flex/Flex.tsx b/HDesign/src/components/Flex/Flex.tsx index eb2530b31..0210669cc 100644 --- a/HDesign/src/components/Flex/Flex.tsx +++ b/HDesign/src/components/Flex/Flex.tsx @@ -1,7 +1,9 @@ /** @jsxImportSource @emotion/react */ +import {css} from '@emotion/react'; + import {StrictPropsWithChildren} from '@/types/strictPropsWithChildren'; import {changeCamelCaseToKebabCase} from '@/utils/ return str.replace(/([a-z])([A-Z])/changeCamelCaseToKebabCase'; -import {css} from '@emotion/react'; + import {FlexDirectionStrictType, FlexProps} from './Flex.type'; const flexStyle = ({ @@ -32,8 +34,8 @@ const flexStyle = ({ }); // TODO: (@weadie) 지정된 프롭 말고 다른 프롭도 가져올 수 있게 하자. -const Flex = ({children, ...props}: StrictPropsWithChildren<FlexProps>) => { +function Flex({children, ...props}: StrictPropsWithChildren<FlexProps>) { return <div css={flexStyle(props)}>{children}</div>; -}; +} export default Flex; diff --git a/HDesign/src/components/IconButton/IconButton.tsx b/HDesign/src/components/IconButton/IconButton.tsx index 9e19ddf21..66d4c34b8 100644 --- a/HDesign/src/components/IconButton/IconButton.tsx +++ b/HDesign/src/components/IconButton/IconButton.tsx @@ -2,7 +2,6 @@ import {forwardRef} from 'react'; import {IconButtonProps} from '@components/IconButton/IconButton.type'; - import {InputDelete, Plus, Buljusa} from '@/assets'; const ICON = { diff --git a/HDesign/src/components/InOutItem/InOutItem.style.ts b/HDesign/src/components/InOutItem/InOutItem.style.ts index b14dedae8..3137d1908 100644 --- a/HDesign/src/components/InOutItem/InOutItem.style.ts +++ b/HDesign/src/components/InOutItem/InOutItem.style.ts @@ -1,6 +1,7 @@ -import {Theme} from '@/theme/theme.type'; import {css} from '@emotion/react'; +import {Theme} from '@/theme/theme.type'; + export const inOutItemStyle = (theme: Theme) => css({ display: 'flex', diff --git a/HDesign/src/components/InOutItem/InOutItem.tsx b/HDesign/src/components/InOutItem/InOutItem.tsx index 37fd8bbd5..7cc99622f 100644 --- a/HDesign/src/components/InOutItem/InOutItem.tsx +++ b/HDesign/src/components/InOutItem/InOutItem.tsx @@ -1,14 +1,16 @@ /** @jsxImportSource @emotion/react */ import React from 'react'; +import Text from '@components/Text/Text'; + import {useTheme} from '@theme/HDesignProvider'; -import {InOutItemProps} from './InOutItem.type'; -import {prefixStyle, textStyle} from './InOutItem.style'; -import Text from '@components/Text/Text'; import IconButton from '../IconButton/IconButton'; import DragHandleItem from '../DragHandleItem/DragHandleItem'; +import {InOutItemProps} from './InOutItem.type'; +import {prefixStyle, textStyle} from './InOutItem.style'; + export const InOutItem: React.FC<InOutItemProps> = ({ names = [], inOutType = 'out', diff --git a/HDesign/src/components/Input/Input.style.ts b/HDesign/src/components/Input/Input.style.ts index be05abb5b..aeedfeb50 100644 --- a/HDesign/src/components/Input/Input.style.ts +++ b/HDesign/src/components/Input/Input.style.ts @@ -1,6 +1,7 @@ import {css} from '@emotion/react'; import {Theme} from '@theme/theme.type'; + import {InputType} from './Input.type'; const inputBoxBackgroundColorByInputType = (theme: Theme, inputType: InputType = 'input') => { diff --git a/HDesign/src/components/Search/Search.stories.tsx b/HDesign/src/components/Search/Search.stories.tsx index 40f7df4b1..d52f74053 100644 --- a/HDesign/src/components/Search/Search.stories.tsx +++ b/HDesign/src/components/Search/Search.stories.tsx @@ -1,6 +1,7 @@ -import React from 'react'; import type {Meta, StoryObj} from '@storybook/react'; +import React from 'react'; + import Search from '@components/Search/Search'; const meta = { @@ -23,7 +24,7 @@ const meta = { disabled: false, placeholder: 'placeholder', searchTerms: ['todari', 'cookie'], - setKeyword: keyword => console.log(keyword), + setKeyword: (keyword: string) => console.log(keyword), }, } satisfies Meta<typeof Search>; diff --git a/HDesign/src/components/Search/Search.style.ts b/HDesign/src/components/Search/Search.style.ts index 413655bd5..230cf3e8e 100644 --- a/HDesign/src/components/Search/Search.style.ts +++ b/HDesign/src/components/Search/Search.style.ts @@ -1,6 +1,7 @@ -import {Theme} from '@/theme/theme.type'; import {css} from '@emotion/react'; +import {Theme} from '@/theme/theme.type'; + export const searchStyle = css({ position: 'relative', diff --git a/HDesign/src/components/Search/Search.tsx b/HDesign/src/components/Search/Search.tsx index 68fc02209..cecdffa52 100644 --- a/HDesign/src/components/Search/Search.tsx +++ b/HDesign/src/components/Search/Search.tsx @@ -1,11 +1,13 @@ /** @jsxImportSource @emotion/react */ +import Flex from '@components/Flex/Flex'; + +import {useTheme} from '@theme/HDesignProvider'; + import Input from '../Input/Input'; import {InputProps} from '../Input/Input.type'; -import {searchStyle, searchTermsStyle} from './Search.style'; + +import {searchStyle, searchTermsStyle, searchTermStyle} from './Search.style'; import useSearch from './useSearch'; -import {searchTermStyle} from './Search.style'; -import {useTheme} from '@theme/HDesignProvider'; -import Flex from '@components/Flex/Flex'; export interface SearchProps extends InputProps { searchTerms: string[]; diff --git a/HDesign/src/components/StepItem/StepItem.style.ts b/HDesign/src/components/StepItem/StepItem.style.ts index 0cf47c7bb..0258b47a4 100644 --- a/HDesign/src/components/StepItem/StepItem.style.ts +++ b/HDesign/src/components/StepItem/StepItem.style.ts @@ -1,6 +1,7 @@ -import {Theme} from '@/theme/theme.type'; import {css} from '@emotion/react'; +import {Theme} from '@/theme/theme.type'; + export const stepItemStyle = (theme: Theme) => css({ display: 'flex', diff --git a/HDesign/src/components/StepItem/StepItem.tsx b/HDesign/src/components/StepItem/StepItem.tsx index c85fe61bc..6f096db12 100644 --- a/HDesign/src/components/StepItem/StepItem.tsx +++ b/HDesign/src/components/StepItem/StepItem.tsx @@ -1,12 +1,14 @@ /** @jsxImportSource @emotion/react */ import {useTheme} from '@/theme/HDesignProvider'; -import {StepItemCustomProps} from './StepItem.type'; -import {nameStyle, personCountStyle, stepItemStyle, totalAmountStyle, totalTitleStyle} from './StepItem.style'; + import Text from '../Text/Text'; import BillItem from '../BillItem/BillItem'; import {BillItemCustomProps} from '../BillItem/BillItem.type'; import Flex from '../Flex/Flex'; +import {nameStyle, personCountStyle, stepItemStyle, totalAmountStyle, totalTitleStyle} from './StepItem.style'; +import {StepItemCustomProps} from './StepItem.type'; + export const StepItem: React.FC<StepItemCustomProps> = ({ name = '', personCount = 0, diff --git a/HDesign/src/components/Switch/Switch.tsx b/HDesign/src/components/Switch/Switch.tsx index 3ac505ff6..17118a6fa 100644 --- a/HDesign/src/components/Switch/Switch.tsx +++ b/HDesign/src/components/Switch/Switch.tsx @@ -1,10 +1,11 @@ /** @jsxImportSource @emotion/react */ import TextButton from '../TextButton/TextButton'; + import {switchContainerStyle} from './Switch.style'; import {SwitchProps} from './Switch.type'; import {useSwitch} from './useSwitch'; -const Switch = ({value = '', initialValue, values, onChange}: SwitchProps) => { +function Switch({value = '', initialValue, values, onChange}: SwitchProps) { const {selectedValue, handleClick} = useSwitch({value, initialValue, values, onChange}); return ( @@ -21,6 +22,6 @@ const Switch = ({value = '', initialValue, values, onChange}: SwitchProps) => { ))} </div> ); -}; +} export default Switch; diff --git a/HDesign/src/components/Tab/Tab.stories.tsx b/HDesign/src/components/Tab/Tab.stories.tsx index 06986fec2..e92495e1a 100644 --- a/HDesign/src/components/Tab/Tab.stories.tsx +++ b/HDesign/src/components/Tab/Tab.stories.tsx @@ -1,6 +1,7 @@ -import React from 'react'; import type {Meta, StoryObj} from '@storybook/react'; +import React from 'react'; + import Tab from '@components/Tab/Tab'; const meta = { diff --git a/HDesign/src/components/Tab/Tab.style.ts b/HDesign/src/components/Tab/Tab.style.ts index 2242261b5..b038fadd1 100644 --- a/HDesign/src/components/Tab/Tab.style.ts +++ b/HDesign/src/components/Tab/Tab.style.ts @@ -1,6 +1,7 @@ -import {Theme} from '@/theme/theme.type'; import {css} from '@emotion/react'; +import {Theme} from '@/theme/theme.type'; + export const tabStyle = css({ display: 'flex', flexDirection: 'column', diff --git a/HDesign/src/components/Tab/Tab.tsx b/HDesign/src/components/Tab/Tab.tsx index 313f62086..4981b9e92 100644 --- a/HDesign/src/components/Tab/Tab.tsx +++ b/HDesign/src/components/Tab/Tab.tsx @@ -2,11 +2,12 @@ import {css} from '@emotion/react'; import React, {useState} from 'react'; +import Text from '@components/Text/Text'; + import {useTheme} from '@theme/HDesignProvider'; import {tabListStyle, tabTextStyle, tabStyle, tabItemStyle, indicatorStyle} from './Tab.style'; import {TabsProps} from './Tab.type'; -import Text from '@components/Text/Text'; const Tab: React.FC<TabsProps> = ({tabs}) => { const {theme} = useTheme(); diff --git a/HDesign/src/components/TextButton/TextButton.style.ts b/HDesign/src/components/TextButton/TextButton.style.ts index e2b602c62..6777b1eed 100644 --- a/HDesign/src/components/TextButton/TextButton.style.ts +++ b/HDesign/src/components/TextButton/TextButton.style.ts @@ -1,6 +1,8 @@ +import {css} from '@emotion/react'; + import {Theme} from '@/theme/theme.type'; + import {TextColor} from './TextButton.type'; -import {css} from '@emotion/react'; interface TextButtonStyleProps { textColor: TextColor; diff --git a/HDesign/src/components/TextButton/TextButton.tsx b/HDesign/src/components/TextButton/TextButton.tsx index c44b7a5c7..9d857c38d 100644 --- a/HDesign/src/components/TextButton/TextButton.tsx +++ b/HDesign/src/components/TextButton/TextButton.tsx @@ -1,8 +1,11 @@ /** @jsxImportSource @emotion/react */ import {forwardRef} from 'react'; -import {TextButtonProps} from './TextButton.type'; -import Text from '../Text/Text'; + import {useTheme} from '@/theme/HDesignProvider'; + +import Text from '../Text/Text'; + +import {TextButtonProps} from './TextButton.type'; import {textButtonStyle} from './TextButton.style'; export const TextButton: React.FC<TextButtonProps> = forwardRef<HTMLButtonElement, TextButtonProps>(function Button( diff --git a/HDesign/src/components/TopNav/TopNav.stories.ts b/HDesign/src/components/TopNav/TopNav.stories.ts index f37845346..f231e8bd7 100644 --- a/HDesign/src/components/TopNav/TopNav.stories.ts +++ b/HDesign/src/components/TopNav/TopNav.stories.ts @@ -1,6 +1,7 @@ import type {Meta, StoryObj} from '@storybook/react'; import TopNav from '@components/TopNav/TopNav'; + import Switch from '../Switch/Switch'; const meta = { diff --git a/HDesign/src/components/TopNav/TopNav.tsx b/HDesign/src/components/TopNav/TopNav.tsx index 75ce368ff..bcfa72260 100644 --- a/HDesign/src/components/TopNav/TopNav.tsx +++ b/HDesign/src/components/TopNav/TopNav.tsx @@ -1,12 +1,14 @@ import {useNavigate} from 'react-router-dom'; + import TextButton from '../TextButton/TextButton'; +import Switch from '../Switch/Switch'; + import {topNavStyle} from './TopNav.style'; import {TopNavProps} from './TopNav.type'; -import Switch from '../Switch/Switch'; // TODO: (@todari) navigation으로 인해 storybook 동작하지 않는 오류 해결해야함 // + 페이지 정하는 것에 따라, navigate 경로 수정해 줘야 함 -const TopNav = ({navType}: TopNavProps) => { +function TopNav({navType}: TopNavProps) { const navigate = useNavigate(); return ( <div css={topNavStyle}> @@ -15,10 +17,10 @@ const TopNav = ({navType}: TopNavProps) => { 뒤로가기 </TextButton> ) : ( - <Switch values={['홈', '관리']} onChange={() => navigate('./')}></Switch> + <Switch values={['홈', '관리']} onChange={() => navigate('./')} /> )} </div> ); -}; +} export default TopNav; diff --git a/HDesign/src/layouts/MainLayout.tsx b/HDesign/src/layouts/MainLayout.tsx index 825aca175..10032b4d8 100644 --- a/HDesign/src/layouts/MainLayout.tsx +++ b/HDesign/src/layouts/MainLayout.tsx @@ -1,12 +1,13 @@ import {PropsWithChildren} from 'react'; + import {Flex} from '..'; interface MainLayoutInterface extends PropsWithChildren {} -export const MainLayout = ({children}: MainLayoutInterface) => { +export function MainLayout({children}: MainLayoutInterface) { return ( <Flex justifyContent="flexStart" flexDirection="column" margin="1rem 0 0 0" gap="1rem" width="100%" height="100%"> {children} </Flex> ); -}; +} From e443f3b54dc7635785492b69cf8d93143a94e661 Mon Sep 17 00:00:00 2001 From: Soyeon Choe <77609591+soi-ha@users.noreply.github.com> Date: Sat, 27 Jul 2024 23:08:49 +0900 Subject: [PATCH 100/178] =?UTF-8?q?feat:=202=EC=B0=A8=20=EC=8A=A4=ED=94=84?= =?UTF-8?q?=EB=A6=B0=ED=8A=B8=20API=20=EC=97=B0=EA=B2=B0=20(#137)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: storybook 관련 dependency 설치 * feat: post api에도 response를 받을 수 있도록 수정 * refactor: parameter가 파스칼케이스인 부분을 카멜 케이스로 수정 * feat: 행사명을 가져오는 api 함수 구현 * feat: interface 수정에 따라 body 변경 * feat: 지출 내역을 추가하는 api 연결 * feat: 최초 참여자를 추가하는 api 연결 * feat: 참여자 수를 조정하는 api 연결 * refactor: name -> title로 파라미터명 수정 * feat: 이벤트아이디를 url에서 불러오는 훅 구현 * feat: 지출 내역, 인원 조정 api연결 후 provider로 전파 * feat: url에서 eventId를 받아오도록 추가 * feat: submit이벤트를 form 엘리먼트에 연결 * remove: 사용하지 않는 파일 제거 * feat: useContext를 사용해 총 가격을 불러오도록 연결 * feat: provider를 사용하기 위한 Layout 컴포넌트 추가 * feat: 디자인시스템 수정에 다른 컴포넌트 호출 형태 변경 * chore: 주석 추가 * remove: 사용하지 않는 파일 제거 * feat: router 에 home, admin 경로에서 띄울 컴포넌트 연결 * fix: 변경된 interface에 맞게 body 수정 * feat: 참여자 목록을 넘겨주지 않고, 참여자 타입 전달 * chore: 불필요한 props 삭제 * feat: 공백된 값 제거 * feat: 네비게이션을 위한 구현 * fix: useStepList훅이 context를 반환하도록 수정 * feat: TopNav 추가 * feat: Admin 페이지 구현 * feat: Home 페이지 구현 * chore: 디자인시스템 라이브러리 업데이트 * chore: await 추가 * feat: stepList를 호출하도록 api 연결 * chore: 사용하지 않는 변수 제거 * chore: lint 적용 * feat: steps를 꺼내서 return하도록 수정 * feat: 인원이 있어야 memberNameList를 갱신하도록 로직 작성 * feat: StepList 의 타입 작성 * design: 불필요한 padding 제거 * chore: 관리 탭에서 StepList를 보여주기 위해 임시로 조건문 제거 * feat: 홈 페이지에서 총 지출 금액 표시 * chore: 디자인 시스템 업데이트 * fix: meta tag 설정 - mixed content, scalable 등 * design: 메인 페이지 및 행사 생성 페이지 디자인 수정 * fix: 새로 고침하면 내역이 출력되지 않는 오류 수정 eventId의 변화에 따라 지출 내역을 다시 호출하도록 종속성을 연결하지 않아서 발생한 문제입니다. * chore: Content-Security-Policy 삭제 * fix: FixedButton disabled 속성 추가 * fix: 행사 이름 입력 페이지 FixedButton disalbed 추가 및 공백 제거 * style: lint 적용 * fix: 불필요한 인자를 넘겨주는 것 제거 * chore: 사용되지 않는 import 제거 * fix: 참여자별 지출 내역을 받아오는 api의 엔드포인트 올바르게 수정 * fix: eventId, 전체 검색 결과에 따라 검색 결과가 보여지도록 수정 * design: 이벤트 홈 타이틀과 탭 사이 공백 제거 * feat: 임시로 행사 이름을 표시하도록 수정 * style: 사용하지 않는 변수 및 import 제거 * design: 전역 스크롤바 숨김 처리 * design: 바텀 버튼만큼 contents 위로 올라오도록 변경 * rename: steList 타입 파일 useStepList 폴더로 이동 후 type.ts로 이름 변경 * chore: 디자인시스템 버전 업데이트 * feat: 검색창 placeholder 참여자 이름 추가 --------- Co-authored-by: 이태훈 <rhymint@gmail.com> Co-authored-by: 김진호 <rlawlsgh1227@gmail.com> Co-authored-by: pakxe <pigkill40@naver.com> --- client/index.html | 3 +- client/package-lock.json | 8 +- client/package.json | 2 +- client/src/apis/fetcher.ts | 16 ++- client/src/apis/request/bill.ts | 8 +- client/src/apis/request/event.ts | 29 +++-- client/src/apis/request/member.ts | 14 ++- client/src/apis/request/report.ts | 4 +- client/src/apis/request/stepList.ts | 8 +- client/src/apis/requestPostEvent.ts | 2 +- .../MemberReportList/MemberReportList.tsx | 6 +- .../SetActionModalContent.tsx | 21 +--- .../SetActionModalContent/SetPurchase.tsx | 16 ++- .../UpdateParticipants.tsx | 24 ++--- .../SetInitialParticipants.tsx | 16 ++- client/src/components/StepList/StepList.tsx | 11 +- client/src/constants/routerUrls.ts | 2 +- client/src/hooks/useDynamicInputPairs.tsx | 17 +-- client/src/hooks/useEventId/useEventId.tsx | 25 +++++ client/src/hooks/useNavSwitch.tsx | 37 +++++++ .../useSearchMemberReportList.tsx | 22 ++-- .../stepList.ts => hooks/useStepList/type.ts} | 16 +-- client/src/hooks/useStepList/useStepList.tsx | 91 ++++++++++++---- client/src/index.css | 5 + client/src/pages/Create/Complete.tsx | 13 +-- client/src/pages/Create/Name.tsx | 32 ++++-- client/src/pages/CreateEvent/CreateEvent.tsx | 27 ----- .../{Event.style.ts => Admin/Admin.style.ts} | 1 + client/src/pages/Event/Admin/Admin.tsx | 97 +++++++++++++++++ client/src/pages/Event/Admin/index.ts | 1 + client/src/pages/Event/Event.tsx | 102 ------------------ client/src/pages/Event/EventLayout.tsx | 23 ++++ client/src/pages/Event/Home/Home.tsx | 40 +++++++ client/src/pages/Event/Home/index.ts | 1 + client/src/pages/Event/index.ts | 2 +- client/src/pages/Home/HomeContent.tsx | 21 ---- client/src/pages/Home/HomeLayout.tsx | 20 ---- client/src/pages/Home/index.ts | 1 - client/src/pages/Main/Main.tsx | 4 +- client/src/router.tsx | 14 +-- client/src/type.d.ts | 18 ++++ 41 files changed, 479 insertions(+), 341 deletions(-) create mode 100644 client/src/hooks/useEventId/useEventId.tsx create mode 100644 client/src/hooks/useNavSwitch.tsx rename client/src/{types/stepList.ts => hooks/useStepList/type.ts} (64%) delete mode 100644 client/src/pages/CreateEvent/CreateEvent.tsx rename client/src/pages/Event/{Event.style.ts => Admin/Admin.style.ts} (85%) create mode 100644 client/src/pages/Event/Admin/Admin.tsx create mode 100644 client/src/pages/Event/Admin/index.ts delete mode 100644 client/src/pages/Event/Event.tsx create mode 100644 client/src/pages/Event/EventLayout.tsx create mode 100644 client/src/pages/Event/Home/Home.tsx create mode 100644 client/src/pages/Event/Home/index.ts delete mode 100644 client/src/pages/Home/HomeContent.tsx delete mode 100644 client/src/pages/Home/HomeLayout.tsx delete mode 100644 client/src/pages/Home/index.ts create mode 100644 client/src/type.d.ts diff --git a/client/index.html b/client/index.html index 05702360a..97edcf3ca 100644 --- a/client/index.html +++ b/client/index.html @@ -2,7 +2,8 @@ <html lang="ko"> <head> <meta charset="UTF-8" /> - <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=0" /> + <meta content="upgrade-insecure-requests" /> <title>행동대장 diff --git a/client/package-lock.json b/client/package-lock.json index 8bc10061f..91269318a 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -12,7 +12,7 @@ "@emotion/react": "^11.11.4", "@types/dotenv-webpack": "^7.0.7", "dotenv-webpack": "^8.1.0", - "haengdong-design": "^0.1.29", + "haengdong-design": "^0.1.35", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.24.1" @@ -6274,9 +6274,9 @@ "dev": true }, "node_modules/haengdong-design": { - "version": "0.1.29", - "resolved": "https://registry.npmjs.org/haengdong-design/-/haengdong-design-0.1.29.tgz", - "integrity": "sha512-yBxmS8PBYOMG6scumzeey2LQMSvlB5kqyd/pIP/ID4WRkvwVo8ScFYO6iV8odFINt4I1Dx2aC/itdk74Pyvv4A==", + "version": "0.1.35", + "resolved": "https://registry.npmjs.org/haengdong-design/-/haengdong-design-0.1.35.tgz", + "integrity": "sha512-JhlZgZXzYfCMV57glEOiI+YKGstGAAOhBOKGad6Mugio/vNVUmInf3/eJPEy/10SM9reizYsSCt7eoyj71ZaSA==", "dependencies": { "@emotion/react": "^11.11.4", "@svgr/webpack": "^8.1.0", diff --git a/client/package.json b/client/package.json index 3c66313b4..cb8e9a714 100644 --- a/client/package.json +++ b/client/package.json @@ -47,7 +47,7 @@ "@emotion/react": "^11.11.4", "@types/dotenv-webpack": "^7.0.7", "dotenv-webpack": "^8.1.0", - "haengdong-design": "^0.1.29", + "haengdong-design": "^0.1.35", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.24.1" diff --git a/client/src/apis/fetcher.ts b/client/src/apis/fetcher.ts index 8df81a2c2..f0bdb9887 100644 --- a/client/src/apis/fetcher.ts +++ b/client/src/apis/fetcher.ts @@ -39,7 +39,7 @@ export const requestGet = async ({headers = {}, ...args}: RequestProps): Prom headers, }); - const data: T = await response.json(); + const data: T = await response!.json(); return data; }; @@ -51,8 +51,16 @@ export const requestPut = ({headers = {}, ...args}: RequestProps) => { return fetcher({method: 'PUT', headers, ...args}); }; -export const requestPost = ({headers = {}, ...args}: RequestProps) => { - return fetcher({method: 'POST', headers, ...args}); +export const requestPost = async ({headers = {}, ...args}: RequestProps): Promise => { + const response = await fetcher({method: 'POST', headers, ...args}); + + const contentType = response!.headers.get('Content-Type'); + if (contentType && contentType.includes('application/json')) { + const data: T = await response!.json(); + return data; + } + + return; }; export const requestDelete = ({headers = {}, ...args}: RequestProps) => { @@ -98,8 +106,8 @@ const errorHandler = async (url: string, options: Options) => { return response; } catch (error) { console.error(error); - throw new Error('아 에러났다;; 인생이 행복해질거에요 에러덕분에요ㅎㅎ'); // throw new ErrorWithHeader(errorMessageHeader, getErrorMessage(error)); + return; } }; diff --git a/client/src/apis/request/bill.ts b/client/src/apis/request/bill.ts index 2e364b944..c07fd758a 100644 --- a/client/src/apis/request/bill.ts +++ b/client/src/apis/request/bill.ts @@ -1,20 +1,18 @@ -import {Bill} from 'types/stepList'; - import {BASE_URL} from '@apis/baseUrl'; import {TEMP_PREFIX} from '@apis/tempPrefix'; import {requestPost} from '@apis/fetcher'; import {WithEventId} from '@apis/withEventId.type'; type RequestAddBillList = { - BillList: Bill[]; + billList: Bill[]; }; -export const requestAddBillList = async ({eventId, BillList}: WithEventId) => { +export const requestAddBillList = async ({eventId, billList}: WithEventId) => { await requestPost({ baseUrl: BASE_URL.HD, endpoint: `${TEMP_PREFIX}/${eventId}/actions/bills`, body: { - actions: BillList, + actions: billList, }, }); }; diff --git a/client/src/apis/request/event.ts b/client/src/apis/request/event.ts index f6ff6d56b..5822267b9 100644 --- a/client/src/apis/request/event.ts +++ b/client/src/apis/request/event.ts @@ -1,18 +1,29 @@ -import {StepList} from 'types/stepList'; - -import {BASE_URL} from '@apis/baseUrl'; import {TEMP_PREFIX} from '@apis/tempPrefix'; -import {requestGet} from '@apis/fetcher'; +import {requestGet, requestPost} from '@apis/fetcher'; +import {WithEventId} from '@apis/withEventId.type'; type RequestCreateNewEvent = { - name: string; + eventName: string; +}; + +type ResponseCreateNewEvent = { + eventId: string; }; -export const requestCreateNewEvent = async ({name}: RequestCreateNewEvent) => { +export const requestCreateNewEvent = async ({eventName}: RequestCreateNewEvent) => { // TODO: (@weadie) 뼈대만 둔 것. header값을 꺼내오는 로직이 필요하다. 또는 바디에 달라고 부탁할 수 있다. - return await requestGet({ - baseUrl: BASE_URL.HD, + return requestPost({ endpoint: TEMP_PREFIX, - body: {name}, + body: {eventName}, + }); +}; + +type ResponseGetEventName = { + eventName: string; +}; + +export const requestGetEventName = async ({eventId}: WithEventId) => { + return requestGet({ + endpoint: `${TEMP_PREFIX}/${eventId}`, }); }; diff --git a/client/src/apis/request/member.ts b/client/src/apis/request/member.ts index 252c85e11..d23563f34 100644 --- a/client/src/apis/request/member.ts +++ b/client/src/apis/request/member.ts @@ -1,20 +1,24 @@ -import {Member} from 'types/stepList'; - import {BASE_URL} from '@apis/baseUrl'; import {TEMP_PREFIX} from '@apis/tempPrefix'; import {requestPost} from '@apis/fetcher'; import {WithEventId} from '@apis/withEventId.type'; type RequestUpdateMemberList = { - MemberList: Member[]; + memberNameList: string[]; + type: MemberType; }; -export const requestUpdateMemberList = async ({eventId, MemberList}: WithEventId) => { +export const requestUpdateMemberList = async ({ + eventId, + type, + memberNameList, +}: WithEventId) => { await requestPost({ baseUrl: BASE_URL.HD, endpoint: `${TEMP_PREFIX}/${eventId}/actions/members`, body: { - actions: MemberList, + members: memberNameList, + status: type, }, }); }; diff --git a/client/src/apis/request/report.ts b/client/src/apis/request/report.ts index 9b714752a..faa6c9185 100644 --- a/client/src/apis/request/report.ts +++ b/client/src/apis/request/report.ts @@ -1,5 +1,3 @@ -import {MemberReport} from 'types/stepList'; - import {BASE_URL} from '@apis/baseUrl'; import {TEMP_PREFIX} from '@apis/tempPrefix'; import {requestGet} from '@apis/fetcher'; @@ -12,7 +10,7 @@ type ResponseMemberReportList = { export const requestMemberReportList = async ({eventId}: WithEventId) => { const {reports} = await requestGet({ baseUrl: BASE_URL.HD, - endpoint: `${TEMP_PREFIX}/${eventId}/actions`, + endpoint: `${TEMP_PREFIX}/${eventId}/actions/reports`, }); return reports; diff --git a/client/src/apis/request/stepList.ts b/client/src/apis/request/stepList.ts index 60ad385e4..e09cb67fd 100644 --- a/client/src/apis/request/stepList.ts +++ b/client/src/apis/request/stepList.ts @@ -1,15 +1,15 @@ -import {Bill, Member, StepList} from 'types/stepList'; - import {BASE_URL} from '@apis/baseUrl'; import {TEMP_PREFIX} from '@apis/tempPrefix'; -import {requestGet, requestPost} from '@apis/fetcher'; +import {requestGet} from '@apis/fetcher'; import {WithEventId} from '@apis/withEventId.type'; // TODO: (@weadie) 현재 토큰을 어떻게 관리할지.. 계속 사용되는데 export const requestStepList = async ({eventId}: WithEventId) => { // TODO: (@weadie) response가 어떻게 오는지 안나와서 data로만 써뒀어요. - return await requestGet({ + const {steps} = await requestGet({ baseUrl: BASE_URL.HD, endpoint: `${TEMP_PREFIX}/${eventId}/actions`, }); + + return steps; }; diff --git a/client/src/apis/requestPostEvent.ts b/client/src/apis/requestPostEvent.ts index cf6b4716e..c03ae02af 100644 --- a/client/src/apis/requestPostEvent.ts +++ b/client/src/apis/requestPostEvent.ts @@ -5,7 +5,7 @@ interface RequestPostEventProps { } export const requestPostEvent = async ({name}: RequestPostEventProps) => { - requestPost({ + await requestPost({ headers: {'Content-Type': 'application/json'}, body: {name}, endpoint: '/api/events', diff --git a/client/src/components/MemberReportList/MemberReportList.tsx b/client/src/components/MemberReportList/MemberReportList.tsx index ebf1cf72e..1004540fa 100644 --- a/client/src/components/MemberReportList/MemberReportList.tsx +++ b/client/src/components/MemberReportList/MemberReportList.tsx @@ -5,15 +5,15 @@ import useSearchMemberReportList from '@hooks/useSearchMemberReportList/useSearc const MemberReportList = () => { const [name, setName] = useState(''); - const {memberReportSearchList} = useSearchMemberReportList({name, eventId: '므와아아아'}); + const {memberReportSearchList} = useSearchMemberReportList({name}); const changeName = ({target}: React.ChangeEvent) => { setName(target.value); }; return ( - - + + ); diff --git a/client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx b/client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx index 93a917652..b3ccd64c9 100644 --- a/client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx +++ b/client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx @@ -1,8 +1,6 @@ import {useState} from 'react'; import {BottomSheet, Switch} from 'haengdong-design'; -import {InOutType, ParticipantType, PurchaseInformation} from '@pages/Event/Event'; - import SetPurchase from './SetPurchase'; import UpdateParticipants from './UpdateParticipants'; import {setActionModalContentStyle, setActionModalContentSwitchContainerStyle} from './SetActionModalContent.style'; @@ -10,29 +8,21 @@ import {setActionModalContentStyle, setActionModalContentSwitchContainerStyle} f export type ActionType = '지출' | '인원'; interface SetActionModalContentProps { - participants: string[]; openBottomSheet: boolean; - setOpenBottomSheet: React.Dispatch>; setOrder: React.Dispatch>; } -const SetActionModalContent = ({ - participants, - openBottomSheet, - - setOpenBottomSheet, - setOrder, -}: SetActionModalContentProps) => { +const SetActionModalContent = ({openBottomSheet, setOpenBottomSheet, setOrder}: SetActionModalContentProps) => { const [action, setAction] = useState('지출'); - const [participantAction, setParticipantAction] = useState('탈주'); + const [inOutAction, setInOutAction] = useState('탈주'); const handleActionTypeChange = (value: string) => { setAction(value as ActionType); }; const handleParticipantTypeChange = (value: string) => { - setParticipantAction(value as InOutType); + setInOutAction(value as InOutType); }; return ( @@ -41,15 +31,14 @@ const SetActionModalContent = ({
{action === '인원' && ( - + )}
{action === '지출' && } {action === '인원' && ( )} diff --git a/client/src/components/Modal/SetActionModalContent/SetPurchase.tsx b/client/src/components/Modal/SetActionModalContent/SetPurchase.tsx index 515c048dd..a83a697a7 100644 --- a/client/src/components/Modal/SetActionModalContent/SetPurchase.tsx +++ b/client/src/components/Modal/SetActionModalContent/SetPurchase.tsx @@ -1,5 +1,7 @@ import {Input, FixedButton} from 'haengdong-design'; +import {useStepList} from '@hooks/useStepList/useStepList'; + import useDynamicInputPairs from '@hooks/useDynamicInputPairs'; import {setPurchaseInputStyle, setPurchaseStyle, setPurchaseInputContainerStyle} from './SetPurchase.style'; @@ -10,11 +12,14 @@ interface SetPurchaseProps { } const SetPurchase = ({setOpenBottomSheet, setOrder}: SetPurchaseProps) => { - const {inputPairs, inputRefs, handleInputChange, handleInputBlur} = useDynamicInputPairs(); + const {inputPairs, inputRefs, handleInputChange, handleInputBlur, getNonEmptyInputPairs} = useDynamicInputPairs(); + const {addBill} = useStepList(); const handleSetPurchaseSubmit = () => { setOrder(prev => prev + 1); - // TODO: (@soha) api 요청시 inputPairs를 보내면 됨 + + // TODO: (@weadie) 요청 실패시 오류 핸들 필요 + addBill(getNonEmptyInputPairs()); setOpenBottomSheet(false); }; @@ -25,8 +30,8 @@ const SetPurchase = ({setOpenBottomSheet, setOrder}: SetPurchaseProps) => {
handleInputChange(index, 'name', e.target.value)} + value={pair.title} + onChange={e => handleInputChange(index, 'title', e.target.value)} onBlur={() => handleInputBlur(index)} placeholder="지출 내역" ref={el => (inputRefs.current[index * 2] = el)} @@ -43,7 +48,8 @@ const SetPurchase = ({setOpenBottomSheet, setOrder}: SetPurchaseProps) => { ))}
diff --git a/client/src/components/Modal/SetActionModalContent/UpdateParticipants.tsx b/client/src/components/Modal/SetActionModalContent/UpdateParticipants.tsx index 72b86faa7..5adc3cd43 100644 --- a/client/src/components/Modal/SetActionModalContent/UpdateParticipants.tsx +++ b/client/src/components/Modal/SetActionModalContent/UpdateParticipants.tsx @@ -1,31 +1,22 @@ import {Input, FixedButton} from 'haengdong-design'; -import {useState} from 'react'; -import {InOutType} from '@pages/Event/Event'; +import {useStepList} from '@hooks/useStepList/useStepList'; import useDynamicInput from '@hooks/useDynamicAdditionalInput'; import {updateParticipantsInputStyle, updateParticipantsStyle} from './UpdateParticipants.style'; interface UpdateParticipantsProps { - participants: string[]; - participantAction: InOutType; + inOutAction: MemberType; setOpenBottomSheet: React.Dispatch>; } -const UpdateParticipants = ({participantAction, participants, setOpenBottomSheet}: UpdateParticipantsProps) => { +const UpdateParticipants = ({inOutAction, setOpenBottomSheet}: UpdateParticipantsProps) => { const {inputs, inputRefs, handleInputChange, handleInputBlur, getNonEmptyInputs} = useDynamicInput(); + const {updateMemberList} = useStepList(); const handleUpdateParticipantsSubmit = () => { - const newParticipants = () => { - if (participantAction === '탈주') { - return participants.filter(participant => !getNonEmptyInputs().includes(participant)); - } else { - return [...participants, ...getNonEmptyInputs()]; - } - }; - - // TODO: (@soha) api 요청시 newParticipants()를 보내면 됨 + updateMemberList({memberNameList: getNonEmptyInputs(), type: inOutAction}); setOpenBottomSheet(false); }; @@ -46,8 +37,9 @@ const UpdateParticipants = ({participantAction, participants, setOpenBottomSheet ))}
diff --git a/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.tsx b/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.tsx index 15a0b0460..e5dda7c96 100644 --- a/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.tsx +++ b/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.tsx @@ -1,5 +1,7 @@ import {Text, Input, BottomSheet, FixedButton} from 'haengdong-design'; +import {useStepList} from '@hooks/useStepList/useStepList'; + import useDynamicInput from '@hooks/useDynamicAdditionalInput'; import {setInitialParticipantsInputGroupStyle, setInitialParticipantsStyle} from './SetInitialParticipants.style'; @@ -7,19 +9,14 @@ import {setInitialParticipantsInputGroupStyle, setInitialParticipantsStyle} from interface SetInitialParticipantsProps { openBottomSheet: boolean; setOpenBottomSheet: React.Dispatch>; - setParticipants: React.Dispatch>; } -const SetInitialParticipants = ({ - openBottomSheet, - setOpenBottomSheet, - setParticipants, -}: SetInitialParticipantsProps) => { +const SetInitialParticipants = ({openBottomSheet, setOpenBottomSheet}: SetInitialParticipantsProps) => { const {inputs, inputRefs, handleInputChange, handleInputBlur, getNonEmptyInputs} = useDynamicInput(); + const {updateMemberList} = useStepList(); const handleSubmit = () => { - setParticipants(getNonEmptyInputs()); - // TODO: (@soha) api 요청시 getNonEmptyInputs() 보낼 형태 생성 + updateMemberList({memberNameList: getNonEmptyInputs(), type: 'IN'}); setOpenBottomSheet(false); }; @@ -42,7 +39,8 @@ const SetInitialParticipants = ({ diff --git a/client/src/components/StepList/StepList.tsx b/client/src/components/StepList/StepList.tsx index 76dedc41b..6e9961f99 100644 --- a/client/src/components/StepList/StepList.tsx +++ b/client/src/components/StepList/StepList.tsx @@ -1,17 +1,22 @@ import {Flex, InOutItem, StepItem} from 'haengdong-design'; import {useStepList} from '@hooks/useStepList/useStepList'; -import {MemberType} from 'types/stepList'; const StepList = () => { const {stepList} = useStepList(); // TODO: (@weadie) if else 구문이 지저분하므로 리펙터링이 필요합니다. return ( - + {stepList.map(step => { if (step.type === 'BILL') { - return ; + return ( + + ); } else if (step.type === 'IN' || step.type === 'OUT') { return name)} />; } else { diff --git a/client/src/constants/routerUrls.ts b/client/src/constants/routerUrls.ts index 228e25c7c..c57ab181e 100644 --- a/client/src/constants/routerUrls.ts +++ b/client/src/constants/routerUrls.ts @@ -2,7 +2,7 @@ export const ROUTER_URLS = { main: '', eventCreateName: '/event/create/name', eventCreateComplete: '/event/create/complete', - event: '/event', + event: '/event', // TODO: (@weadie) baseurl을 어떻게 관리할 것인가? eventManage: '/event/:eventId/admin', home: '/event/:eventId/home', }; diff --git a/client/src/hooks/useDynamicInputPairs.tsx b/client/src/hooks/useDynamicInputPairs.tsx index db5347dd8..b6f86b000 100644 --- a/client/src/hooks/useDynamicInputPairs.tsx +++ b/client/src/hooks/useDynamicInputPairs.tsx @@ -1,12 +1,10 @@ import {useEffect, useRef, useState} from 'react'; -import {PurchaseInformation} from '@pages/Event/Event'; - const useDynamicInputPairs = () => { - const [inputPairs, setInputPairs] = useState([{name: '', price: 0}]); + const [inputPairs, setInputPairs] = useState([{title: '', price: 0}]); const inputRefs = useRef<(HTMLInputElement | null)[]>([]); - const handleInputChange = (index: number, field: 'name' | 'price', value: string) => { + const handleInputChange = (index: number, field: 'title' | 'price', value: string) => { const newInputPairs = [...inputPairs]; newInputPairs[index] = { ...newInputPairs[index], @@ -17,13 +15,17 @@ const useDynamicInputPairs = () => { const handleInputBlur = (index: number) => { const currentPair = inputPairs[index]; - if (currentPair.name.trim() === '' && currentPair.price === 0) { + if (currentPair.title.trim() === '' && currentPair.price === 0) { setInputPairs(prev => prev.filter((_, i) => i !== index)); - } else if (currentPair.name.trim() !== '' && currentPair.price !== 0 && index === inputPairs.length - 1) { - setInputPairs(prev => [...prev, {name: '', price: 0}]); + } else if (currentPair.title.trim() !== '' && currentPair.price !== 0 && index === inputPairs.length - 1) { + setInputPairs(prev => [...prev, {title: '', price: 0}]); } }; + const getNonEmptyInputPairs = () => { + return inputPairs.filter(currentPair => currentPair.title.trim() !== '' && currentPair.price !== 0); + }; + useEffect(() => { if (inputRefs.current.length > 0) { const lastInputPair = inputRefs.current.slice(-2); @@ -33,6 +35,7 @@ const useDynamicInputPairs = () => { return { inputPairs, + getNonEmptyInputPairs, inputRefs, handleInputChange, handleInputBlur, diff --git a/client/src/hooks/useEventId/useEventId.tsx b/client/src/hooks/useEventId/useEventId.tsx new file mode 100644 index 000000000..ca3775f8e --- /dev/null +++ b/client/src/hooks/useEventId/useEventId.tsx @@ -0,0 +1,25 @@ +import {useEffect, useState} from 'react'; +import {useLocation} from 'react-router-dom'; + +const useEventId = () => { + const [eventId, setEventId] = useState(''); + const location = useLocation(); + + const extractIdFromUrl = (url: string) => { + const regex = /\/event\/([a-zA-Z0-9-]+)\//; + const match = url.match(regex); + return match ? match[1] : null; + }; + + const curEventId = extractIdFromUrl(location.pathname) ?? ''; + + useEffect(() => { + setEventId(curEventId); + }, []); + + return { + eventId, + }; +}; + +export default useEventId; diff --git a/client/src/hooks/useNavSwitch.tsx b/client/src/hooks/useNavSwitch.tsx new file mode 100644 index 000000000..7ecd3def8 --- /dev/null +++ b/client/src/hooks/useNavSwitch.tsx @@ -0,0 +1,37 @@ +import {useState} from 'react'; +import {useLocation, useNavigate} from 'react-router-dom'; + +const PATH_TABLE: Record = { + 홈: 'home', + 관리: 'admin', +}; + +const PATH_DISPLAY_TABLE: Record = { + home: '홈', + admin: '관리', +}; + +const useNavSwitch = () => { + const paths = ['홈', '관리']; + const location = useLocation(); + const navigate = useNavigate(); + + const pathArray = location.pathname.split('/'); + const basePath = pathArray.slice(0, -1).join('/'); + const lastPath = pathArray[pathArray.length - 1]; + + const [nav, setNav] = useState(PATH_DISPLAY_TABLE[lastPath]); + + const onChange = (displayName: string) => { + setNav(displayName); + navigate(`${basePath}/${PATH_TABLE[displayName]}`); + }; + + return { + nav, + paths, + onChange, + }; +}; + +export default useNavSwitch; diff --git a/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.tsx b/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.tsx index 589317f7d..02c07b80a 100644 --- a/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.tsx +++ b/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.tsx @@ -1,41 +1,37 @@ import {useEffect, useState} from 'react'; -import {MemberReport} from 'types/stepList'; import {requestMemberReportList} from '@apis/request/report'; - -import {WithEventId} from '@apis/withEventId.type'; - -import memberReportSearchJsonList from '@mocks/memberReportSearchList.json'; - -const memberReportSearchMockList = memberReportSearchJsonList as MemberReport[]; +import useEventId from '@hooks/useEventId/useEventId'; type UseSearchMemberReportListParams = { name: string; }; -const useSearchMemberReportList = ({name, eventId}: WithEventId) => { - const [memberReportList, setMemberReportList] = useState(memberReportSearchMockList); +const useSearchMemberReportList = ({name}: UseSearchMemberReportListParams) => { + const [memberReportList, setMemberReportList] = useState([]); const [memberReportSearchList, setMemberReportSearchList] = useState([]); + const {eventId} = useEventId(); useEffect(() => { const fetchMemberReportList = async () => { // TODO: (@weadie) cors 고쳐지면 주석 풀게요. - // const memberReportListData = await requestMemberReportList({eventId}); + // TODO: (@weadie) eventId에 의존하는 두 개의 훅에 대한 리펙토링 필요 + if (eventId === '') return; - const memberReportListData = memberReportSearchMockList; + const memberReportListData = await requestMemberReportList({eventId}); setMemberReportList(memberReportListData); }; fetchMemberReportList(); - }, []); + }, [eventId]); // TODO: (@weadie) 글자가 완성될 때마다 아래 로직이 실행되어야 합니다. useEffect(() => { if (name === '') setMemberReportSearchList(memberReportList); setMemberReportSearchList(memberReportList.filter(memberReport => memberReport.name.includes(name))); - }, [name]); + }, [name, memberReportList]); return { memberReportSearchList, diff --git a/client/src/types/stepList.ts b/client/src/hooks/useStepList/type.ts similarity index 64% rename from client/src/types/stepList.ts rename to client/src/hooks/useStepList/type.ts index f106306e9..6d9b78de1 100644 --- a/client/src/types/stepList.ts +++ b/client/src/hooks/useStepList/type.ts @@ -1,11 +1,7 @@ -export type MemberType = 'IN' | 'OUT'; - -// TODO: (@weadie) 준 데이터 형식에서 steps를 빼내 flat하게 사용중. 일관성있게 하는게 좋긴 하나 사용시 번거로움이 있을 거라고 판단. -export type StepList = (MemberStep | BillStep)[]; - export type Step = { type: MemberType | 'BILL'; stepName: string | null; + members: string[]; actions: (BillAction | MemberAction)[]; }; @@ -40,13 +36,3 @@ export type Member = { name: string; status: MemberType; }; - -export type Bill = { - title: string; - price: number; -}; - -export type MemberReport = { - name: string; - price: number; -}; diff --git a/client/src/hooks/useStepList/useStepList.tsx b/client/src/hooks/useStepList/useStepList.tsx index 9adb2d684..52d2a78d6 100644 --- a/client/src/hooks/useStepList/useStepList.tsx +++ b/client/src/hooks/useStepList/useStepList.tsx @@ -1,25 +1,65 @@ -import {PropsWithChildren, createContext, useEffect, useState} from 'react'; +import {PropsWithChildren, createContext, useContext, useEffect, useState} from 'react'; -import {BillAction, MemberType, StepList} from 'types/stepList'; +import useEventId from '@hooks/useEventId/useEventId'; +import {requestAddBillList} from '@apis/request/bill'; +import {requestUpdateMemberList} from '@apis/request/member'; +import {requestStepList} from '@apis/request/stepList'; -import stepListJsonData from '@mocks/stepList.json'; +import {BillAction, BillStep, MemberStep} from './type.ts'; -const stepListMockData = stepListJsonData as StepList; +interface StepListContextProps { + stepList: (BillStep | MemberStep)[]; + getTotalPrice: () => number; + addBill: (billList: Bill[]) => Promise; + updateMemberList: ({type, memberNameList}: {type: MemberType; memberNameList: string[]}) => Promise; + memberNameList: string[]; +} -const useStepList = () => { - const [stepList, setStepList] = useState(stepListMockData); +export const StepListContext = createContext(null); // TODO: (@weadie) 인자를 어떻게 줘야 하는지 고민하기. + +const StepListProvider = ({children}: PropsWithChildren) => { + const [stepList, setStepList] = useState<(BillStep | MemberStep)[]>([]); + const [memberNameList, setNameMemberList] = useState([]); + + const {eventId} = useEventId(); useEffect(() => { + if (eventId === '') return; + + refreshStepList(); + // TODO: (@weadie) useEffect를 꼭 써야하는가? - // 초기 리스트 불러서 setActionList - }, []); + }, [eventId]); + + const refreshStepList = async () => { + const stepList = await requestStepList({eventId}); + + if (stepList.length !== 0) { + setNameMemberList(stepList[stepList.length - 1].members); + } - const updateMemberList = (type: MemberType, memberList: string[]) => { - // api를 호출하고 set한다 + setStepList(stepList); }; - const addBill = (title: string, price: number) => { - // api를 호출하고 set한다. + const updateMemberList = async ({type, memberNameList}: {type: MemberType; memberNameList: string[]}) => { + try { + await requestUpdateMemberList({eventId, type, memberNameList}); + + // TODO: (@weadie) 클라이언트 단에서 멤버 목록을 관리하기 위한 로직. 개선이 필요하다. + if (type === 'IN') setNameMemberList(prev => [...prev, ...memberNameList]); + if (type === 'OUT') setNameMemberList(prev => prev.filter(name => !memberNameList.includes(name))); + + refreshStepList(); + } catch (error) { + alert(error); + } + }; + + const addBill = async (billList: Bill[]) => { + // TODO: (@weadie) 에러 처리 + await requestAddBillList({eventId, billList}); + + refreshStepList(); }; const calculateBillSum = (actions: BillAction[]) => { @@ -35,15 +75,28 @@ const useStepList = () => { }, 0); }; - return {stepList, getTotalPrice}; + return ( + + {children} + + ); }; -const StepListContext = createContext([]); // TODO: (@weadie) 인자를 어떻게 줘야 하는지 고민하기. - -const StepListProvider = ({children}: PropsWithChildren) => { - const {stepList} = useStepList(); +export const useStepList = () => { + const context = useContext(StepListContext); - return {children}; + if (!context) { + throw new Error('useStepList는 StepListProvider 내에서 사용되어야 합니다.'); + } + return context; }; -export {useStepList, StepListProvider}; +export default StepListProvider; diff --git a/client/src/index.css b/client/src/index.css index 8ebdb5ba8..2f63176f6 100644 --- a/client/src/index.css +++ b/client/src/index.css @@ -2,6 +2,11 @@ body { max-width: 768px; height: 100lvh; margin: 0 auto; + + overflow-y: scroll; + &::-webkit-scrollbar { + display: none; + } } section { diff --git a/client/src/pages/Create/Complete.tsx b/client/src/pages/Create/Complete.tsx index b4496d0cd..786979607 100644 --- a/client/src/pages/Create/Complete.tsx +++ b/client/src/pages/Create/Complete.tsx @@ -1,6 +1,6 @@ import {useEffect, useState} from 'react'; import {useLocation, useNavigate} from 'react-router-dom'; -import {FixedButton, MainLayout, Title} from 'haengdong-design'; +import {FixedButton, MainLayout, Title, TopNav} from 'haengdong-design'; import {ROUTER_URLS} from '@constants/routerUrls'; @@ -11,11 +11,12 @@ const CompleteCreateEvent = () => { useEffect(() => { const getUrl = async () => { - const eventTitle = location.search; - // console.log(eventTitle); + // TODO: (@weadie) eventId를 location에서 불러오는 로직 함수로 분리해서 재사용 + const params = new URLSearchParams(location.search); + const eventId = params.get('eventId'); - // const url = await fetch(); - setUrl('hangsapage'); + // TODO: (@weadie) eventId가 없는 경우에 대한 처리 필요 + setUrl(eventId ?? ''); }; getUrl(); @@ -23,7 +24,7 @@ const CompleteCreateEvent = () => { return ( - {/* */} + } /> + <TopNav> + <Back /> + </TopNav> <Title title="행사 이름 입력" description="시작할 행사 이름을 입력해 주세요." /> - <form onSubmit={submitEventTitle}> + <form onSubmit={submitEventName} style={{padding: '0 1rem'}}> <Input - value={eventTitle} - onChange={event => setEventTitle(event.target.value)} + value={eventName} + onChange={event => setEventName(event.target.value)} + onBlur={() => setEventName(eventName.trim())} placeholder="ex) 행동대장 야유회" /> - <FixedButton onClick={() => navigate(ROUTER_URLS.eventCreateComplete)}>행동 개시!</FixedButton> + <FixedButton disabled={!eventName.length}>행동 개시!</FixedButton> </form> </MainLayout> ); diff --git a/client/src/pages/CreateEvent/CreateEvent.tsx b/client/src/pages/CreateEvent/CreateEvent.tsx deleted file mode 100644 index 9697200e0..000000000 --- a/client/src/pages/CreateEvent/CreateEvent.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import {useState} from 'react'; -import {useNavigate} from 'react-router-dom'; - -import {ROUTER_URLS} from '@constants/routerUrls'; - -const CreateEvent = () => { - const [eventTitle, setEventTitle] = useState(''); - const navigate = useNavigate(); - - const submitEventTitle = (event: React.FormEvent<HTMLFormElement>) => { - event.preventDefault(); - navigate(`${ROUTER_URLS.eventCreateName}?${new URLSearchParams({title: eventTitle})}`); - }; - - return ( - <section> - <h1>행사 생성하기</h1> - <h3>시작할 행사 이름을 입력해 주세요.</h3> - <form onSubmit={submitEventTitle}> - <input value={eventTitle} onChange={event => setEventTitle(event.target.value)} /> - <button>행동 개시!</button> - </form> - </section> - ); -}; - -export default CreateEvent; diff --git a/client/src/pages/Event/Event.style.ts b/client/src/pages/Event/Admin/Admin.style.ts similarity index 85% rename from client/src/pages/Event/Event.style.ts rename to client/src/pages/Event/Admin/Admin.style.ts index 15e2443b4..2025006d4 100644 --- a/client/src/pages/Event/Event.style.ts +++ b/client/src/pages/Event/Admin/Admin.style.ts @@ -6,4 +6,5 @@ export const ReceiptStyle = () => flexDirection: 'column', gap: '8px', padding: '0 8px', + paddingBottom: '8.75rem', }); diff --git a/client/src/pages/Event/Admin/Admin.tsx b/client/src/pages/Event/Admin/Admin.tsx new file mode 100644 index 000000000..bda03da55 --- /dev/null +++ b/client/src/pages/Event/Admin/Admin.tsx @@ -0,0 +1,97 @@ +import {useEffect, useState} from 'react'; +import {Title, FixedButton} from 'haengdong-design'; + +import StepList from '@components/StepList/StepList'; +import {useStepList} from '@hooks/useStepList/useStepList'; +import {requestGetEventName} from '@apis/request/event'; +import useEventId from '@hooks/useEventId/useEventId'; + +import {SetActionModalContent, SetInitialParticipants} from '@components/Modal'; + +import {ReceiptStyle} from './Admin.style'; + +export type PurchaseInformation = { + title: string; + price: number; +}; + +export type ParticipantType = { + name: string; + type: InOutType; +}; + +interface ModalRenderingProps { + memberNameList: string[]; + openBottomSheet: boolean; + setOrder: React.Dispatch<React.SetStateAction<number>>; + setOpenBottomSheet: React.Dispatch<React.SetStateAction<boolean>>; +} + +const ModalRendering = ({memberNameList, openBottomSheet, setOrder, setOpenBottomSheet}: ModalRenderingProps) => { + switch (memberNameList.length) { + case 0: + return <SetInitialParticipants setOpenBottomSheet={setOpenBottomSheet} openBottomSheet={openBottomSheet} />; + + default: + return ( + <SetActionModalContent + setOrder={setOrder} + setOpenBottomSheet={setOpenBottomSheet} + openBottomSheet={openBottomSheet} + /> + ); + } +}; + +const Admin = () => { + const [openBottomSheet, setOpenBottomSheet] = useState(false); + const [order, setOrder] = useState<number>(1); + + // TODO: (@weadie) eventName이 새로고침시 공간이 없다가 생겨나 레이아웃이 움직이는 문제 + const [eventName, setEventName] = useState(' '); + + const {getTotalPrice, memberNameList} = useStepList(); + + const {eventId} = useEventId(); + + // TODO: (@weadie) 아래 로직을 훅으로 분리합니다. + useEffect(() => { + if (eventId === '') return; + + const getEventName = async () => { + const {eventName} = await requestGetEventName({eventId: eventId ?? ''}); + + setEventName(eventName); + }; + + getEventName(); + }, [eventId]); + + return ( + <> + <Title + title={eventName} + description="“초기인원 설정하기” 버튼을 눌러서 행사 초기 인원을 설정해 주세요." + price={getTotalPrice()} + /> + <section css={ReceiptStyle}> + <StepList /> + {/* TODO: (@soha) 추후 버튼 width 화면에 맞게 수정 */} + <FixedButton + children={memberNameList.length === 0 ? '초기인원 설정하기' : '행동 추가하기'} + onClick={() => setOpenBottomSheet(prev => !prev)} + /> + {openBottomSheet && ( + <ModalRendering + memberNameList={memberNameList} + setOrder={setOrder} + setOpenBottomSheet={setOpenBottomSheet} + openBottomSheet={openBottomSheet} + /> + )} + </section> + </> + ); +}; + +export default Admin; diff --git a/client/src/pages/Event/Admin/index.ts b/client/src/pages/Event/Admin/index.ts new file mode 100644 index 000000000..9799a7485 --- /dev/null +++ b/client/src/pages/Event/Admin/index.ts @@ -0,0 +1 @@ +export {default as AdminPage} from './Admin'; diff --git a/client/src/pages/Event/Event.tsx b/client/src/pages/Event/Event.tsx deleted file mode 100644 index 79c1f9950..000000000 --- a/client/src/pages/Event/Event.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import {useState} from 'react'; -import {TopNav, Title, FixedButton, StepItem, InOutItem, MainLayout} from 'haengdong-design'; - -import StepList from '@components/StepList/StepList'; -import {useStepList} from '@hooks/useStepList/useStepList'; -import {StepListProvider} from '@hooks/useStepList/useStepList'; - -import {SetActionModalContent, SetInitialParticipants} from '@components/Modal'; - -import {ReceiptStyle} from './Event.style'; - -export type PurchaseInformation = { - name: string; - price: number; -}; - -export type InOutType = '늦참' | '탈주'; - -export type ParticipantType = { - name: string; - type: InOutType; -}; - -interface ModalRenderingProps { - participants: string[]; - openBottomSheet: boolean; - - setOrder: React.Dispatch<React.SetStateAction<number>>; - setOpenBottomSheet: React.Dispatch<React.SetStateAction<boolean>>; - setParticipants: React.Dispatch<React.SetStateAction<string[]>>; -} - -const ModalRendering = ({ - participants, - setOrder, - setOpenBottomSheet, - setParticipants, - openBottomSheet, -}: ModalRenderingProps) => { - switch (participants.length) { - case 0: - return ( - <SetInitialParticipants - setParticipants={setParticipants} - setOpenBottomSheet={setOpenBottomSheet} - openBottomSheet={openBottomSheet} - /> - ); - - default: - return ( - <SetActionModalContent - setOrder={setOrder} - participants={participants} - setOpenBottomSheet={setOpenBottomSheet} - openBottomSheet={openBottomSheet} - /> - ); - } -}; - -const Event = () => { - const [openBottomSheet, setOpenBottomSheet] = useState(false); - const [participants, setParticipants] = useState<string[]>([]); - const [order, setOrder] = useState<number>(0); - - const {getTotalPrice} = useStepList(); - - return ( - <MainLayout backgroundColor="gray"> - <TopNav navType={'home'} /> - <Title - title="행동대장 야유회" - description="“초기인원 설정하기” 버튼을 눌러서 행사 초기 인원을 설정해 주세요." - price={getTotalPrice()} - /> - <section css={ReceiptStyle}> - {order > 0 && ( - // TODO: (@soha) order가 0일때 기본 Step 뜨기 - <StepListProvider> - <StepList /> - </StepListProvider> - )} - {/* TODO: (@soha) 추후 버튼 width 화면에 맞게 수정 */} - <FixedButton - children={participants.length === 0 ? '초기인원 설정하기' : '행동 추가하기'} - onClick={() => setOpenBottomSheet(prev => !prev)} - /> - {openBottomSheet && - ModalRendering({ - participants, - setOrder, - setParticipants, - setOpenBottomSheet, - openBottomSheet, - })} - </section> - </MainLayout> - ); -}; - -export default Event; diff --git a/client/src/pages/Event/EventLayout.tsx b/client/src/pages/Event/EventLayout.tsx new file mode 100644 index 000000000..2b2b439de --- /dev/null +++ b/client/src/pages/Event/EventLayout.tsx @@ -0,0 +1,23 @@ +import {MainLayout, TopNav, Switch} from 'haengdong-design'; +import {Outlet} from 'react-router-dom'; + +import StepListProvider from '@hooks/useStepList/useStepList'; + +import useNavSwitch from '@hooks/useNavSwitch'; + +const EventLayout = () => { + const {nav, paths, onChange} = useNavSwitch(); + + return ( + <StepListProvider> + <MainLayout backgroundColor="gray"> + <TopNav> + <Switch value={nav} values={paths} onChange={onChange} /> + </TopNav> + <Outlet /> + </MainLayout> + </StepListProvider> + ); +}; + +export default EventLayout; diff --git a/client/src/pages/Event/Home/Home.tsx b/client/src/pages/Event/Home/Home.tsx new file mode 100644 index 000000000..8ff195cb8 --- /dev/null +++ b/client/src/pages/Event/Home/Home.tsx @@ -0,0 +1,40 @@ +import {Tab, Tabs, Title} from 'haengdong-design'; +import {useEffect, useState} from 'react'; + +import MemberReportList from '@components/MemberReportList/MemberReportList'; +import StepList from '@components/StepList/StepList'; +import {useStepList} from '@hooks/useStepList/useStepList'; +import useEventId from '@hooks/useEventId/useEventId'; +import {requestGetEventName} from '@apis/request/event'; + +const HomeContent = () => { + const {getTotalPrice} = useStepList(); + const {eventId} = useEventId(); + + // TODO: (@soha) 행사 이름 나중에 따로 분리해야 함 + const [eventName, setEventName] = useState(' '); + + useEffect(() => { + if (eventId === '') return; + + const getEventName = async () => { + const {eventName} = await requestGetEventName({eventId: eventId ?? ''}); + + setEventName(eventName); + }; + + getEventName(); + }, [eventId]); + + return ( + <div> + <Title title={eventName} price={getTotalPrice()} /> + <Tabs tabsContainerStyle={{gap: '1rem'}}> + <Tab label="전체 지출 내역" content={<StepList />} /> + <Tab label="참여자 별 내역" content={<MemberReportList />} /> + </Tabs> + </div> + ); +}; + +export default HomeContent; diff --git a/client/src/pages/Event/Home/index.ts b/client/src/pages/Event/Home/index.ts new file mode 100644 index 000000000..75e27b8a3 --- /dev/null +++ b/client/src/pages/Event/Home/index.ts @@ -0,0 +1 @@ +export {default as HomePage} from './Home'; diff --git a/client/src/pages/Event/index.ts b/client/src/pages/Event/index.ts index fa85db27a..af2aa805d 100644 --- a/client/src/pages/Event/index.ts +++ b/client/src/pages/Event/index.ts @@ -1 +1 @@ -export {default as EventPage} from './Event'; +export {default as EventPage} from './EventLayout'; diff --git a/client/src/pages/Home/HomeContent.tsx b/client/src/pages/Home/HomeContent.tsx deleted file mode 100644 index 171729636..000000000 --- a/client/src/pages/Home/HomeContent.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import {Tab, Tabs, Title} from 'haengdong-design'; - -import MemberReportList from '@components/MemberReportList/MemberReportList'; -import StepList from '@components/StepList/StepList'; -import {useStepList} from '@hooks/useStepList/useStepList'; - -const HomeContent = () => { - const {getTotalPrice} = useStepList(); - - return ( - <div> - <Title title="행동대장 야유회" price={getTotalPrice()} /> - <Tabs> - <Tab label="전체 지출 내역" content={<StepList />} /> - <Tab label="참여자 별 내역" content={<MemberReportList />} /> - </Tabs> - </div> - ); -}; - -export default HomeContent; diff --git a/client/src/pages/Home/HomeLayout.tsx b/client/src/pages/Home/HomeLayout.tsx deleted file mode 100644 index 8cae579d6..000000000 --- a/client/src/pages/Home/HomeLayout.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import {Flex, MainLayout, TopNav} from 'haengdong-design'; - -import {StepListProvider} from '@hooks/useStepList/useStepList'; - -import HomeContent from './HomeContent'; - -const HomeLayout = () => { - return ( - <StepListProvider> - <MainLayout backgroundColor="gray"> - <TopNav navType="home" /> - <Flex flexDirection="column" gap="1rem"> - <HomeContent /> - </Flex> - </MainLayout> - </StepListProvider> - ); -}; - -export default HomeLayout; diff --git a/client/src/pages/Home/index.ts b/client/src/pages/Home/index.ts deleted file mode 100644 index fde362f5c..000000000 --- a/client/src/pages/Home/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {default as HomePage} from './HomeLayout'; diff --git a/client/src/pages/Main/Main.tsx b/client/src/pages/Main/Main.tsx index 1cb9f6b26..dfd7c406e 100644 --- a/client/src/pages/Main/Main.tsx +++ b/client/src/pages/Main/Main.tsx @@ -1,5 +1,5 @@ import {useNavigate} from 'react-router-dom'; -import {FixedButton, MainLayout, Title} from 'haengdong-design'; +import {FixedButton, MainLayout, Title, TopNav} from 'haengdong-design'; import {ROUTER_URLS} from '@constants/routerUrls'; @@ -8,7 +8,7 @@ const Main = () => { return ( <MainLayout> - {/* <TopNav navType="back" /> */} + <TopNav children={<></>} /> <Title title="행동대장" description="랜딩페이지입니다." /> <FixedButton onClick={() => navigate(ROUTER_URLS.eventCreateName)}>행사 생성하기</FixedButton> </MainLayout> diff --git a/client/src/router.tsx b/client/src/router.tsx index a84ea18e5..70f7a1e71 100644 --- a/client/src/router.tsx +++ b/client/src/router.tsx @@ -1,9 +1,11 @@ import {createBrowserRouter} from 'react-router-dom'; +import {AdminPage} from '@pages/Event/Admin'; +import {HomePage} from '@pages/Event/Home'; + import {MainPage} from '@pages/Main'; import {CreateNamePage, CreateCompletePage} from '@pages/Create'; import {EventPage} from '@pages/Event'; -import {HomePage} from '@pages/Home'; import {ROUTER_URLS} from '@constants/routerUrls'; @@ -28,12 +30,12 @@ const router = createBrowserRouter([ element: <CreateCompletePage />, }, { - path: ROUTER_URLS.eventManage, + path: ROUTER_URLS.event, element: <EventPage />, - }, - { - path: ROUTER_URLS.home, - element: <HomePage />, + children: [ + {path: ROUTER_URLS.eventManage, element: <AdminPage />}, + {path: ROUTER_URLS.home, element: <HomePage />}, + ], }, ], }, diff --git a/client/src/type.d.ts b/client/src/type.d.ts new file mode 100644 index 000000000..a81318e4c --- /dev/null +++ b/client/src/type.d.ts @@ -0,0 +1,18 @@ +type MemberType = 'IN' | 'OUT'; + +type InOutType = '늦참' | '탈주'; + +type MemberReport = { + name: string; + price: number; +}; + +type Bill = { + title: string; + price: number; +}; + +// TODO: (@weadie) 준 데이터 형식에서 steps를 빼내 flat하게 사용중. 일관성있게 하는게 좋긴 하나 사용시 번거로움이 있을 거라고 판단. +type StepList = { + steps: (MemberStep | BillStep)[]; +}; From 4d8697a1214debd729e92766ca8c642b59de6e29 Mon Sep 17 00:00:00 2001 From: JUHA <84626225+khabh@users.noreply.github.com> Date: Sun, 28 Jul 2024 16:44:04 +0900 Subject: [PATCH 101/178] =?UTF-8?q?refactor:=20=EB=8F=84=EC=BB=A4=20?= =?UTF-8?q?=EA=B3=84=EC=A0=95=20=EA=B4=80=EB=A0=A8=20=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?secrets=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95=20(#139)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/backend-push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/backend-push.yml b/.github/workflows/backend-push.yml index be973a6a9..d385a69c8 100644 --- a/.github/workflows/backend-push.yml +++ b/.github/workflows/backend-push.yml @@ -68,4 +68,4 @@ jobs: run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/haengdong-backend-dev - name: Docker run - run: sudo docker run -d -p 8080:8080 --name haengdong-backend-dev haengdong/haengdong-backend-dev + run: sudo docker run -d -p 8080:8080 --name haengdong-backend-dev ${{ secrets.DOCKER_USERNAME }}/haengdong-backend-dev From ee1030c6ca49d0e1a4baa472a519dd29675fdacd Mon Sep 17 00:00:00 2001 From: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> Date: Mon, 29 Jul 2024 18:07:51 +0900 Subject: [PATCH 102/178] =?UTF-8?q?feat:=202=EC=B0=A8=20=EC=8A=A4=ED=94=84?= =?UTF-8?q?=EB=A6=B0=ED=8A=B8=20=EB=94=94=EC=9E=90=EC=9D=B8=20=EC=8B=9C?= =?UTF-8?q?=EC=8A=A4=ED=85=9C=20=EC=88=98=EC=A0=95=20(#83)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * design: Title Component width 100%로 수정 * design: TopNav width 100%로 수정 * fix: index.tsx export 수정 * chore: v0.1.2 배포 * design: input 좌우 1rem 추가 * feat: MainLayout 추가 * chore: v0.1.3 배포 * feat: TopNav none 타입 추가 * chore: storybook-addon-react-router-v6 dev dependency 추가 * fix: ExpenseItem button props 넣을 수 있도록 수정 * design: button cursor pointer 전역설정 * refactor: BottomSheet component 구조 수정 * chore: v0.1.4 배포 * refactor: tab components 합성방식으로 변경 * feat: Flex component backgroundColor 받을 수 있도록 변경 * fix: 주석이 xml 내부에서 적용안되던 오류 해결 * chore: v0.1.5 배포 * refactor: flex background prop 로직 처리 방법 변경 * feat: MainLayout backgroundColor prop 추가 * fix: flex backgroundColor defaultValue 제거 * chore: v0.1.6 배포 * fix: MainLayout margin padding으로 변경 * fix: Switch 및 TopNav 내부 로직 변경 * test: Switch storybook 수정 * fix: TopNav navigate currentPath를 이용하도록 수정 * feat: v0.1.18 배포 * fix: TopNav navigate 변경 * design: tab item과 panel 사이에 gap 넣을 수 있도록 설정 및 flex container 사용 * refactor: in out type uppercase로 수정 * design: in out item font size 변경 및 텍스트 바꿔서 작성한 내용 수정 * test: InOutItem storybook 수정 * chore: v0.1.20 배포 * design: hasDragableItem 비활성화 시 마진 수정 * fix: props 네이밍 스토리북에 반영 * fix: navigate 뒤로가기 3번 발생하는 이슈 해결 * chore: v0.1.22 배포 * fix: Switch 내부의 불필요한 로직 제거 * chore: v0.1.23 배포 * fix: navigate path 로직 변경 * fix: 새로고침 됐을 때 해당 location 페이지를 유지하도록 수정 * style: children이 없는 태그 스스로 닫도록 수정 * style: todo 주석 제거 * chore: v0.1.25 배포 * design: fixedButton position 변경 * chore: v0.1.26 배포 * fix: 라우팅 변경 이동 오류 해결 * chore: v0.1.27 배포 * chore: v0.1.28 배포 * fix: location set 로직을 home 모드에서만 작동하도록 변경 * chore: v0.1.29 배포 * fix: TopNav navigation 로직 외부에서 넣도록 변경 * chore: v0.1.30 배포 * fix: index.ts 경로 문제로 제거 * chore: v0.1.13 배포 * chore: v0.1.32 배포 * fix: Fixed Button 하단 고정되도록 변경 * chore: v0.1.33 배포 * v0.1.35 배포 * fix: 가격과 원을 붙여서 표기 * fix: TopNav가 children이 없어도 작동하도록 변경 * fix: children이 필수가 아니도록 변경 * remove: 사용하지 않는 NavSwitch 제거 * chore: 파이프라인 테스트를 위한 push * chore: 파이프라인 테스트를 위한 push * remove: merge를 위한 /sever dir 삭제 * style: lint 적용 --------- Co-authored-by: 이태훈 <rhymint@gmail.com> Co-authored-by: pakxe <pigkill40@naver.com> --- HDesign/package-lock.json | 561 ++---------------- HDesign/package.json | 3 +- HDesign/src/components/BillItem/BillItem.tsx | 2 +- .../BottomSheet/BottomSheet.stories.tsx | 20 +- .../BottomSheet/BottomSheet.style.ts | 2 +- .../components/BottomSheet/BottomSheet.tsx | 10 +- .../BottomSheet/BottomSheet.type.ts | 5 +- .../components/BottomSheet/useBottomSheet.ts | 23 +- .../components/ExpenseList/ExpenseList.tsx | 12 +- .../ExpenseList/ExpenseList.type.ts | 4 +- .../FixedButton/FixedButton.style.ts | 5 +- HDesign/src/components/Flex/Flex.style.ts | 45 ++ HDesign/src/components/Flex/Flex.tsx | 35 +- HDesign/src/components/Flex/Flex.type.ts | 9 +- .../InOutItem/InOutItem.stories.tsx | 4 +- .../components/InOutItem/InOutItem.style.ts | 4 +- .../src/components/InOutItem/InOutItem.tsx | 18 +- .../components/InOutItem/InOutItem.type.ts | 2 +- HDesign/src/components/Input/Input.style.ts | 2 +- .../src/components/Search/Search.stories.tsx | 4 +- HDesign/src/components/StepItem/StepItem.tsx | 2 +- .../src/components/Switch/Switch.stories.tsx | 4 - HDesign/src/components/Switch/Switch.tsx | 15 +- HDesign/src/components/Switch/Switch.type.ts | 3 +- HDesign/src/components/Switch/useSwitch.ts | 24 - HDesign/src/components/Tab/Tab.stories.tsx | 26 - HDesign/src/components/Tab/Tab.tsx | 55 -- HDesign/src/components/Tab/Tab.type.ts | 8 - HDesign/src/components/Tabs/Tab.tsx | 8 + HDesign/src/components/Tabs/Tab.type.ts | 16 + HDesign/src/components/Tabs/Tabs.stories.tsx | 31 + .../{Tab/Tab.style.ts => Tabs/Tabs.style.ts} | 12 - HDesign/src/components/Tabs/Tabs.tsx | 53 ++ HDesign/src/components/Title/Title.tsx | 4 +- HDesign/src/components/TopNav/Back.tsx | 17 + .../src/components/TopNav/TopNav.stories.ts | 29 - .../src/components/TopNav/TopNav.stories.tsx | 50 ++ HDesign/src/components/TopNav/TopNav.style.ts | 7 + HDesign/src/components/TopNav/TopNav.tsx | 34 +- HDesign/src/components/TopNav/TopNav.type.ts | 5 - HDesign/src/index.tsx | 10 +- HDesign/src/layouts/ContentLayout.tsx | 25 + HDesign/src/layouts/MainLayout.tsx | 18 +- HDesign/src/theme/GlobalStyle.ts | 4 + client/src/pages/Main/Main.tsx | 2 + server/.gitignore | 244 -------- server/Dockerfile | 9 - server/build.gradle | 40 -- server/gradle/wrapper/gradle-wrapper.jar | Bin 43453 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - server/gradlew | 249 -------- server/gradlew.bat | 92 --- server/settings.gradle | 1 - .../haengdong/HaengdongApplication.java | 13 - .../haengdong/application/ActionService.java | 37 -- .../application/BillActionService.java | 44 -- .../haengdong/application/EventService.java | 91 --- .../application/MemberActionFactory.java | 82 --- .../application/MemberActionService.java | 60 -- .../request/BillActionAppRequest.java | 14 - .../application/request/EventAppRequest.java | 10 - .../request/MemberActionSaveAppRequest.java | 12 - .../request/MemberActionsSaveAppRequest.java | 6 - .../response/ActionAppResponse.java | 54 -- .../response/CurrentMemberAppResponse.java | 10 - .../response/EventAppResponse.java | 10 - .../response/EventDetailAppResponse.java | 10 - .../response/MemberBillReportAppResponse.java | 4 - .../server/haengdong/config/WebConfig.java | 27 - .../haengdong/domain/action/Action.java | 42 -- .../domain/action/ActionRepository.java | 21 - .../haengdong/domain/action/BillAction.java | 70 --- .../domain/action/BillActionRepository.java | 14 - .../domain/action/CurrentMembers.java | 66 --- .../haengdong/domain/action/MemberAction.java | 62 -- .../domain/action/MemberActionRepository.java | 15 - .../domain/action/MemberActionStatus.java | 19 - .../domain/action/MemberBillReport.java | 75 --- .../domain/action/MemberGroupIdProvider.java | 11 - .../server/haengdong/domain/event/Event.java | 54 -- .../domain/event/EventRepository.java | 11 - .../haengdong/domain/event/EventStep.java | 28 - .../domain/event/EventTokenProvider.java | 12 - .../haengdong/exception/ErrorResponse.java | 10 - .../exception/GlobalExceptionHandler.java | 43 -- .../exception/HaengdongErrorCode.java | 24 - .../exception/HaengdongException.java | 32 - .../presentation/ActionController.java | 26 - .../presentation/BillActionController.java | 29 - .../presentation/EventController.java | 43 -- .../presentation/MemberActionController.java | 39 -- .../request/BillActionSaveRequest.java | 19 - .../request/BillActionsSaveRequest.java | 14 - .../request/EventSaveRequest.java | 15 - .../request/MemberActionsSaveRequest.java | 22 - .../presentation/response/ActionResponse.java | 20 - .../response/ActionsResponse.java | 28 - .../response/CurrentMemberResponse.java | 10 - .../response/CurrentMembersResponse.java | 15 - .../response/EventDetailResponse.java | 10 - .../presentation/response/EventResponse.java | 10 - .../response/MemberBillReportResponse.java | 10 - .../response/MemberBillReportsResponse.java | 15 - .../presentation/response/StepResponse.java | 57 -- server/src/main/resources/application.yml | 31 - server/src/main/resources/config | 1 - .../application/ActionServiceTest.java | 79 --- .../application/BillActionServiceTest.java | 65 -- .../application/EventServiceTest.java | 110 ---- .../application/MemberActionFactoryTest.java | 217 ------- .../application/MemberActionServiceTest.java | 92 --- .../haengdong/domain/action/ActionTest.java | 30 - .../domain/action/BillActionTest.java | 58 -- .../domain/action/CurrentMembersTest.java | 58 -- .../domain/action/MemberBillReportTest.java | 43 -- .../haengdong/domain/event/EventTest.java | 37 -- .../presentation/ActionControllerTest.java | 49 -- .../BillActionControllerTest.java | 69 --- .../presentation/EventControllerTest.java | 66 --- .../MemberActionControllerTest.java | 67 --- .../response/StepResponseTest.java | 57 -- server/src/test/resources/application.yml | 18 - 122 files changed, 439 insertions(+), 4057 deletions(-) create mode 100644 HDesign/src/components/Flex/Flex.style.ts delete mode 100644 HDesign/src/components/Switch/useSwitch.ts delete mode 100644 HDesign/src/components/Tab/Tab.stories.tsx delete mode 100644 HDesign/src/components/Tab/Tab.tsx delete mode 100644 HDesign/src/components/Tab/Tab.type.ts create mode 100644 HDesign/src/components/Tabs/Tab.tsx create mode 100644 HDesign/src/components/Tabs/Tab.type.ts create mode 100644 HDesign/src/components/Tabs/Tabs.stories.tsx rename HDesign/src/components/{Tab/Tab.style.ts => Tabs/Tabs.style.ts} (82%) create mode 100644 HDesign/src/components/Tabs/Tabs.tsx create mode 100644 HDesign/src/components/TopNav/Back.tsx delete mode 100644 HDesign/src/components/TopNav/TopNav.stories.ts create mode 100644 HDesign/src/components/TopNav/TopNav.stories.tsx delete mode 100644 HDesign/src/components/TopNav/TopNav.type.ts create mode 100644 HDesign/src/layouts/ContentLayout.tsx delete mode 100644 server/.gitignore delete mode 100644 server/Dockerfile delete mode 100644 server/build.gradle delete mode 100644 server/gradle/wrapper/gradle-wrapper.jar delete mode 100644 server/gradle/wrapper/gradle-wrapper.properties delete mode 100755 server/gradlew delete mode 100644 server/gradlew.bat delete mode 100644 server/settings.gradle delete mode 100644 server/src/main/java/server/haengdong/HaengdongApplication.java delete mode 100644 server/src/main/java/server/haengdong/application/ActionService.java delete mode 100644 server/src/main/java/server/haengdong/application/BillActionService.java delete mode 100644 server/src/main/java/server/haengdong/application/EventService.java delete mode 100644 server/src/main/java/server/haengdong/application/MemberActionFactory.java delete mode 100644 server/src/main/java/server/haengdong/application/MemberActionService.java delete mode 100644 server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java delete mode 100644 server/src/main/java/server/haengdong/application/request/EventAppRequest.java delete mode 100644 server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java delete mode 100644 server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java delete mode 100644 server/src/main/java/server/haengdong/application/response/ActionAppResponse.java delete mode 100644 server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java delete mode 100644 server/src/main/java/server/haengdong/application/response/EventAppResponse.java delete mode 100644 server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java delete mode 100644 server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java delete mode 100644 server/src/main/java/server/haengdong/config/WebConfig.java delete mode 100644 server/src/main/java/server/haengdong/domain/action/Action.java delete mode 100644 server/src/main/java/server/haengdong/domain/action/ActionRepository.java delete mode 100644 server/src/main/java/server/haengdong/domain/action/BillAction.java delete mode 100644 server/src/main/java/server/haengdong/domain/action/BillActionRepository.java delete mode 100644 server/src/main/java/server/haengdong/domain/action/CurrentMembers.java delete mode 100644 server/src/main/java/server/haengdong/domain/action/MemberAction.java delete mode 100644 server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java delete mode 100644 server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java delete mode 100644 server/src/main/java/server/haengdong/domain/action/MemberBillReport.java delete mode 100644 server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java delete mode 100644 server/src/main/java/server/haengdong/domain/event/Event.java delete mode 100644 server/src/main/java/server/haengdong/domain/event/EventRepository.java delete mode 100644 server/src/main/java/server/haengdong/domain/event/EventStep.java delete mode 100644 server/src/main/java/server/haengdong/domain/event/EventTokenProvider.java delete mode 100644 server/src/main/java/server/haengdong/exception/ErrorResponse.java delete mode 100644 server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java delete mode 100644 server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java delete mode 100644 server/src/main/java/server/haengdong/exception/HaengdongException.java delete mode 100644 server/src/main/java/server/haengdong/presentation/ActionController.java delete mode 100644 server/src/main/java/server/haengdong/presentation/BillActionController.java delete mode 100644 server/src/main/java/server/haengdong/presentation/EventController.java delete mode 100644 server/src/main/java/server/haengdong/presentation/MemberActionController.java delete mode 100644 server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java delete mode 100644 server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java delete mode 100644 server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java delete mode 100644 server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java delete mode 100644 server/src/main/java/server/haengdong/presentation/response/ActionResponse.java delete mode 100644 server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java delete mode 100644 server/src/main/java/server/haengdong/presentation/response/CurrentMemberResponse.java delete mode 100644 server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java delete mode 100644 server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java delete mode 100644 server/src/main/java/server/haengdong/presentation/response/EventResponse.java delete mode 100644 server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java delete mode 100644 server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java delete mode 100644 server/src/main/java/server/haengdong/presentation/response/StepResponse.java delete mode 100644 server/src/main/resources/application.yml delete mode 160000 server/src/main/resources/config delete mode 100644 server/src/test/java/server/haengdong/application/ActionServiceTest.java delete mode 100644 server/src/test/java/server/haengdong/application/BillActionServiceTest.java delete mode 100644 server/src/test/java/server/haengdong/application/EventServiceTest.java delete mode 100644 server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java delete mode 100644 server/src/test/java/server/haengdong/application/MemberActionServiceTest.java delete mode 100644 server/src/test/java/server/haengdong/domain/action/ActionTest.java delete mode 100644 server/src/test/java/server/haengdong/domain/action/BillActionTest.java delete mode 100644 server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java delete mode 100644 server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java delete mode 100644 server/src/test/java/server/haengdong/domain/event/EventTest.java delete mode 100644 server/src/test/java/server/haengdong/presentation/ActionControllerTest.java delete mode 100644 server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java delete mode 100644 server/src/test/java/server/haengdong/presentation/EventControllerTest.java delete mode 100644 server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java delete mode 100644 server/src/test/java/server/haengdong/presentation/response/StepResponseTest.java delete mode 100644 server/src/test/resources/application.yml diff --git a/HDesign/package-lock.json b/HDesign/package-lock.json index d6b1de8f4..3747523df 100644 --- a/HDesign/package-lock.json +++ b/HDesign/package-lock.json @@ -1,12 +1,12 @@ { "name": "haengdong-design", - "version": "0.1.3", + "version": "0.1.35", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "haengdong-design", - "version": "0.1.3", + "version": "0.1.35", "license": "ISC", "dependencies": { "@emotion/react": "^11.11.4", @@ -45,6 +45,7 @@ "globals": "^15.8.0", "prettier": "3.3.2", "storybook": "^8.2.2", + "storybook-addon-react-router-v6": "^2.0.15", "ts-loader": "^9.5.1", "tsc-alias": "^1.8.10", "typescript": "^5.5.3", @@ -2322,358 +2323,6 @@ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@esbuild/win32-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", @@ -4438,150 +4087,6 @@ } } }, - "node_modules/@swc/core-darwin-arm64": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.5.7.tgz", - "integrity": "sha512-bZLVHPTpH3h6yhwVl395k0Mtx8v6CGhq5r4KQdAoPbADU974Mauz1b6ViHAJ74O0IVE5vyy7tD3OpkQxL/vMDQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-darwin-x64": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.5.7.tgz", - "integrity": "sha512-RpUyu2GsviwTc2qVajPL0l8nf2vKj5wzO3WkLSHAHEJbiUZk83NJrZd1RVbEknIMO7+Uyjh54hEh8R26jSByaw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.5.7.tgz", - "integrity": "sha512-cTZWTnCXLABOuvWiv6nQQM0hP6ZWEkzdgDvztgHI/+u/MvtzJBN5lBQ2lue/9sSFYLMqzqff5EHKlFtrJCA9dQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.5.7.tgz", - "integrity": "sha512-hoeTJFBiE/IJP30Be7djWF8Q5KVgkbDtjySmvYLg9P94bHg9TJPSQoC72tXx/oXOgXvElDe/GMybru0UxhKx4g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.5.7.tgz", - "integrity": "sha512-+NDhK+IFTiVK1/o7EXdCeF2hEzCiaRSrb9zD7X2Z7inwWlxAntcSuzZW7Y6BRqGQH89KA91qYgwbnjgTQ22PiQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.5.7.tgz", - "integrity": "sha512-25GXpJmeFxKB+7pbY7YQLhWWjkYlR+kHz5I3j9WRl3Lp4v4UD67OGXwPe+DIcHqcouA1fhLhsgHJWtsaNOMBNg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-x64-musl": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.5.7.tgz", - "integrity": "sha512-0VN9Y5EAPBESmSPPsCJzplZHV26akC0sIgd3Hc/7S/1GkSMoeuVL+V9vt+F/cCuzr4VidzSkqftdP3qEIsXSpg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.5.7.tgz", - "integrity": "sha512-RtoNnstBwy5VloNCvmvYNApkTmuCe4sNcoYWpmY7C1+bPR+6SOo8im1G6/FpNem8AR5fcZCmXHWQ+EUmRWJyuA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.5.7.tgz", - "integrity": "sha512-Xm0TfvcmmspvQg1s4+USL3x8D+YPAfX2JHygvxAnCJ0EHun8cm2zvfNBcsTlnwYb0ybFWXXY129aq1wgFC9TpQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, "node_modules/@swc/core-win32-x64-msvc": { "version": "1.5.7", "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.5.7.tgz", @@ -6671,6 +6176,12 @@ "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", "dev": true }, + "node_modules/compare-versions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", + "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", + "dev": true + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -8895,20 +8406,6 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -11786,6 +11283,15 @@ "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", "dev": true }, + "node_modules/react-inspector": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-6.0.2.tgz", + "integrity": "sha512-x+b7LxhmHXjHoU/VrFAzw5iutsILRoYyDq97EDYdFpPLcvqtEzk4ZSZSQjnFPbr5T57tLXnHcqFYoN1pI6u8uQ==", + "dev": true, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -12518,6 +12024,37 @@ "url": "https://opencollective.com/storybook" } }, + "node_modules/storybook-addon-react-router-v6": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/storybook-addon-react-router-v6/-/storybook-addon-react-router-v6-2.0.15.tgz", + "integrity": "sha512-4vOYIQwehlQLyXaCT9K0Iu0po2Z+pANGsqkfm/BQuAEjE9MoN7vrsrQLHINhKbmQVtNMmuS/oBR3GGNbqQ1gew==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "compare-versions": "^6.0.0", + "react-inspector": "6.0.2" + }, + "peerDependencies": { + "@storybook/blocks": "^7.0.0", + "@storybook/channels": "^7.0.0", + "@storybook/components": "^7.0.0", + "@storybook/core-events": "^7.0.0", + "@storybook/manager-api": "^7.0.0", + "@storybook/preview-api": "^7.0.0", + "@storybook/theming": "^7.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-router-dom": "^6.4.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/storybook/node_modules/commander": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", diff --git a/HDesign/package.json b/HDesign/package.json index b077aa3ba..b587d3be8 100644 --- a/HDesign/package.json +++ b/HDesign/package.json @@ -1,6 +1,6 @@ { "name": "haengdong-design", - "version": "0.1.3", + "version": "0.1.35", "description": "", "main": "./dist/index.js", "module": "./dist/index.js", @@ -49,6 +49,7 @@ "globals": "^15.8.0", "prettier": "3.3.2", "storybook": "^8.2.2", + "storybook-addon-react-router-v6": "^2.0.15", "ts-loader": "^9.5.1", "tsc-alias": "^1.8.10", "typescript": "^5.5.3", diff --git a/HDesign/src/components/BillItem/BillItem.tsx b/HDesign/src/components/BillItem/BillItem.tsx index bf5d916cd..f73c5d32d 100644 --- a/HDesign/src/components/BillItem/BillItem.tsx +++ b/HDesign/src/components/BillItem/BillItem.tsx @@ -25,7 +25,7 @@ export const BillItem: React.FC<BillItemProps> = ({ {name} </Text> <Text css={textStyle(theme)} size="body"> - {price.toLocaleString('ko-kr')} 원 + {price.toLocaleString('ko-kr')}원 </Text> </Flex> </DragHandleItem> diff --git a/HDesign/src/components/BottomSheet/BottomSheet.stories.tsx b/HDesign/src/components/BottomSheet/BottomSheet.stories.tsx index 943dfa46b..48288fb6c 100644 --- a/HDesign/src/components/BottomSheet/BottomSheet.stories.tsx +++ b/HDesign/src/components/BottomSheet/BottomSheet.stories.tsx @@ -14,19 +14,15 @@ const meta = { // layout: 'centered', }, argTypes: { - fixedButtonVariants: { + fixedButtonProps: { description: '', - control: {type: 'select'}, - options: ['', 'primary', 'secondary', 'tertiary'], - }, - fixedButtonText: { - description: '', - control: {type: 'text'}, + control: {type: 'object'}, }, }, args: { - fixedButtonVariants: 'primary', - fixedButtonText: '하단 고정 버튼이에요', + fixedButtonProps: { + variants: 'primary', + }, }, } satisfies Meta<typeof BottomSheet>; @@ -36,8 +32,10 @@ type Story = StoryObj<typeof meta>; export const Playground: Story = { args: { - fixedButtonVariants: 'primary', - fixedButtonText: '하단 고정 버튼이에요', + fixedButtonProps: { + variants: 'primary', + children: '하단 고정 버튼', + }, }, render: ({...args}) => { const [isOpened, setIsOpened] = useState(false); diff --git a/HDesign/src/components/BottomSheet/BottomSheet.style.ts b/HDesign/src/components/BottomSheet/BottomSheet.style.ts index c2dd93fb3..4968206f1 100644 --- a/HDesign/src/components/BottomSheet/BottomSheet.style.ts +++ b/HDesign/src/components/BottomSheet/BottomSheet.style.ts @@ -16,7 +16,7 @@ export const dimmedLayerStyle = (theme: Theme) => export const bottomSheetContainerStyle = (theme: Theme) => css({ - position: 'absolute', + position: 'fixed', display: 'flex', flexDirection: 'column', alignItems: 'center', diff --git a/HDesign/src/components/BottomSheet/BottomSheet.tsx b/HDesign/src/components/BottomSheet/BottomSheet.tsx index 510b428be..d0f286cc8 100644 --- a/HDesign/src/components/BottomSheet/BottomSheet.tsx +++ b/HDesign/src/components/BottomSheet/BottomSheet.tsx @@ -2,23 +2,23 @@ import {createPortal} from 'react-dom'; import {BottomSheetProps} from '@components/BottomSheet/BottomSheet.type'; -import {useBottomSheet} from '@components/BottomSheet/useBottomSheet'; import FixedButton from '@components/FixedButton/FixedButton'; import {useTheme} from '@theme/HDesignProvider'; +import {useBottomSheet} from './useBottomSheet'; import {bottomSheetContainerStyle, dimmedLayerStyle, indicatorStyle} from './BottomSheet.style'; const BottomSheet: React.FC<BottomSheetProps> = ({ - fixedButtonVariants = 'primary', isOpened = false, children, - fixedButtonText, + fixedButtonProps, ...props }: BottomSheetProps) => { const {theme} = useTheme(); const {opened, handleClose} = useBottomSheet({isOpened, ...props}); + // TODO: (@todari) : children 길이 길 때 overflow button에 안가리는 영역 처리 return createPortal( <> {opened && ( @@ -27,9 +27,7 @@ const BottomSheet: React.FC<BottomSheetProps> = ({ <div css={bottomSheetContainerStyle(theme)}> <div css={indicatorStyle(theme)} /> {children} - {(fixedButtonVariants || fixedButtonText) && ( - <FixedButton variants={fixedButtonVariants} children={fixedButtonText} /> - )} + {fixedButtonProps && <FixedButton {...fixedButtonProps} />} </div> </> )} diff --git a/HDesign/src/components/BottomSheet/BottomSheet.type.ts b/HDesign/src/components/BottomSheet/BottomSheet.type.ts index 365f9f498..312fe3c29 100644 --- a/HDesign/src/components/BottomSheet/BottomSheet.type.ts +++ b/HDesign/src/components/BottomSheet/BottomSheet.type.ts @@ -4,6 +4,8 @@ import {ButtonVariants} from '@components/Button/Button.type'; import {Theme} from '@theme/theme.type'; +import {FixedButtonProps} from '../FixedButton/FixedButton.type'; + export interface BottomSheetStyleProps { theme?: Theme; } @@ -12,8 +14,7 @@ export interface BottomSheetCustomProps { isOpened?: boolean; onChangeOpen?: () => void; onChangeClose?: () => void; - fixedButtonVariants?: ButtonVariants; - fixedButtonText?: string; + fixedButtonProps?: FixedButtonProps; } export type BottomSheetOptionProps = BottomSheetStyleProps & BottomSheetCustomProps; diff --git a/HDesign/src/components/BottomSheet/useBottomSheet.ts b/HDesign/src/components/BottomSheet/useBottomSheet.ts index f67796979..ca2274e19 100644 --- a/HDesign/src/components/BottomSheet/useBottomSheet.ts +++ b/HDesign/src/components/BottomSheet/useBottomSheet.ts @@ -1,23 +1,36 @@ -import {useEffect, useState} from 'react'; +import {useCallback, useEffect, useState} from 'react'; interface UseBottomSheetProps { isOpened: boolean; onChangeClose?: () => void; + onChangeOpen?: () => void; } -export const useBottomSheet = ({isOpened, onChangeClose}: UseBottomSheetProps) => { - const [opened, setOpened] = useState(isOpened); +export const useBottomSheet = ({isOpened, onChangeClose, onChangeOpen}: UseBottomSheetProps) => { + const [opened, setOpened] = useState(false); useEffect(() => { setOpened(isOpened); + if (!isOpened) { + handleClose(); + } else { + handleOpen(); + } }, [isOpened]); - const handleClose = () => { + const handleClose = useCallback(() => { setOpened(false); if (onChangeClose) { onChangeClose(); } - }; + }, []); + + const handleOpen = useCallback(() => { + setOpened(true); + if (onChangeOpen) { + onChangeOpen(); + } + }, []); useEffect(() => { document.body.style.overflow = 'hidden'; diff --git a/HDesign/src/components/ExpenseList/ExpenseList.tsx b/HDesign/src/components/ExpenseList/ExpenseList.tsx index 8dbc71858..2990458bb 100644 --- a/HDesign/src/components/ExpenseList/ExpenseList.tsx +++ b/HDesign/src/components/ExpenseList/ExpenseList.tsx @@ -2,29 +2,34 @@ import Text from '@components/Text/Text'; + import {Arrow} from '@assets/index'; import {useTheme} from '@theme/HDesignProvider'; +import {useTheme} from '@theme/HDesignProvider'; + import {ExpenseItemProps, ExpenseListProps} from './ExpenseList.type'; import {expenseItemStyle, expenseListStyle, expenseItemLeftStyle, TextStyle} from './ExpenseList.style'; // TODO: (@soha) 따로 파일 분리할까 고민중.. 여기서만 사용할 것 같긴 한데.. 흠 -function ExpenseItem({name, price}: ExpenseItemProps) { +function ExpenseItem({name, price, ...buttonProps}: ExpenseItemProps) { const {theme} = useTheme(); return ( - <button css={expenseItemStyle}> + <button css={expenseItemStyle} {...buttonProps}> <Text size="bodyBold" css={TextStyle(theme)}> {name} </Text> <div css={expenseItemLeftStyle}> - <Text css={TextStyle(theme)}>{price.toLocaleString('ko-kr')} 원</Text> + <Text css={TextStyle(theme)}>{price.toLocaleString('ko-kr')}원</Text> <Arrow /> </div> </button> ); } +} +function ExpenseList({expenseList = []}: ExpenseListProps) { function ExpenseList({expenseList = []}: ExpenseListProps) { const {theme} = useTheme(); return ( @@ -35,5 +40,6 @@ function ExpenseList({expenseList = []}: ExpenseListProps) { </div> ); } +} export default ExpenseList; diff --git a/HDesign/src/components/ExpenseList/ExpenseList.type.ts b/HDesign/src/components/ExpenseList/ExpenseList.type.ts index 9ab2aa8bb..939cd2f68 100644 --- a/HDesign/src/components/ExpenseList/ExpenseList.type.ts +++ b/HDesign/src/components/ExpenseList/ExpenseList.type.ts @@ -1,8 +1,10 @@ -export interface ExpenseItemProps { +export interface ExpenseItemCustomProps { name: string; price: number; } +export type ExpenseItemProps = React.ComponentProps<'button'> & ExpenseItemCustomProps; + export type ExpenseListProps = { expenseList: ExpenseItemProps[]; }; diff --git a/HDesign/src/components/FixedButton/FixedButton.style.ts b/HDesign/src/components/FixedButton/FixedButton.style.ts index dc9f96eab..19e011893 100644 --- a/HDesign/src/components/FixedButton/FixedButton.style.ts +++ b/HDesign/src/components/FixedButton/FixedButton.style.ts @@ -8,9 +8,10 @@ import {Theme} from '@theme/theme.type'; export const fixedButtonContainerStyle = (theme: Theme) => css({ display: 'flex', - position: 'absolute', - + position: 'fixed', + maxWidth: '768px', inset: 'auto 0 0', + margin: '0 auto', backgroundColor: theme.colors.white, boxSizing: 'border-box', }); diff --git a/HDesign/src/components/Flex/Flex.style.ts b/HDesign/src/components/Flex/Flex.style.ts new file mode 100644 index 000000000..c86f1b64d --- /dev/null +++ b/HDesign/src/components/Flex/Flex.style.ts @@ -0,0 +1,45 @@ +import {css} from '@emotion/react'; + +import {changeCamelCaseToKebabCase} from '@/utils/ return str.replace(/([a-z])([A-Z])/changeCamelCaseToKebabCase'; + +import {FlexDirectionStrictType, FlexProps} from './Flex.type'; + +export const flexStyle = ({ + justifyContent = 'flexStart', + alignItems = 'stretch', + flexDirection = 'row', + gap = '0', + padding = '0', + paddingInline = '0', + margin = '0', + width = 'auto', + height = 'auto', + backgroundColor, + theme, + ...rest +}: FlexProps) => + css({ + display: 'flex', + justifyContent: changeCamelCaseToKebabCase(justifyContent), + alignItems: changeCamelCaseToKebabCase(alignItems), + // TODO: (@weadie) as를 사용하지 않으면 방법이 없음. css의 flexDirection속성은 string을 받지 않고 명확한 속성명(ex row-reverse)를 받고 싶어함. 다만 as를 사용해도 된다고 생각한 근거는 케밥함수가 FlexDirectionType에 명시된 모든 타입을 정확하게 변환하며, 받는 문자열이 FlexDirectionType에 제한되기 때문. + flexDirection: changeCamelCaseToKebabCase(flexDirection) as FlexDirectionStrictType, + gap, + padding, + paddingInline, + margin, + width, + height, + ...rest, + + backgroundColor: (() => { + switch (backgroundColor) { + case 'white': + return theme?.colors.white; + case 'gray': + return theme?.colors.grayContainer; + default: + return 'none'; + } + })(), + }); diff --git a/HDesign/src/components/Flex/Flex.tsx b/HDesign/src/components/Flex/Flex.tsx index 0210669cc..57a5e7332 100644 --- a/HDesign/src/components/Flex/Flex.tsx +++ b/HDesign/src/components/Flex/Flex.tsx @@ -2,40 +2,15 @@ import {css} from '@emotion/react'; import {StrictPropsWithChildren} from '@/types/strictPropsWithChildren'; -import {changeCamelCaseToKebabCase} from '@/utils/ return str.replace(/([a-z])([A-Z])/changeCamelCaseToKebabCase'; +import {useTheme} from '@/theme/HDesignProvider'; -import {FlexDirectionStrictType, FlexProps} from './Flex.type'; - -const flexStyle = ({ - justifyContent = 'flexStart', - alignItems = 'stretch', - flexDirection = 'row', - gap = '0', - padding = '0', - paddingInline = '0', - margin = '0', - width = 'auto', - height = 'auto', - ...rest -}: FlexProps) => - css({ - display: 'flex', - justifyContent: changeCamelCaseToKebabCase(justifyContent), - alignItems: changeCamelCaseToKebabCase(alignItems), - // TODO: (@weadie) as를 사용하지 않으면 방법이 없음. css의 flexDirection속성은 string을 받지 않고 명확한 속성명(ex row-reverse)를 받고 싶어함. 다만 as를 사용해도 된다고 생각한 근거는 케밥함수가 FlexDirectionType에 명시된 모든 타입을 정확하게 변환하며, 받는 문자열이 FlexDirectionType에 제한되기 때문. - flexDirection: changeCamelCaseToKebabCase(flexDirection) as FlexDirectionStrictType, - gap, - padding, - paddingInline, - margin, - width, - height, - ...rest, - }); +import {FlexProps} from './Flex.type'; +import {flexStyle} from './Flex.style'; // TODO: (@weadie) 지정된 프롭 말고 다른 프롭도 가져올 수 있게 하자. function Flex({children, ...props}: StrictPropsWithChildren<FlexProps>) { - return <div css={flexStyle(props)}>{children}</div>; + const {theme} = useTheme(); + return <div css={flexStyle({theme, ...props})}>{children}</div>; } export default Flex; diff --git a/HDesign/src/components/Flex/Flex.type.ts b/HDesign/src/components/Flex/Flex.type.ts index aeb90bc20..75467e97e 100644 --- a/HDesign/src/components/Flex/Flex.type.ts +++ b/HDesign/src/components/Flex/Flex.type.ts @@ -1,5 +1,8 @@ +import {Theme} from '@/theme/theme.type'; + export type FlexDirectionType = 'row' | 'column' | 'rowReverse' | 'columnReverse'; export type FlexDirectionStrictType = 'row' | 'column' | 'row-reverse' | 'column-reverse'; +export type FlexBackgroundColor = 'gray' | 'white'; export interface FlexProps { justifyContent?: 'flexStart' | 'center' | 'flexEnd' | 'spaceBetween' | 'spaceAround' | 'spaceEvenly'; @@ -11,8 +14,6 @@ export interface FlexProps { margin?: string; width?: string; height?: string; -} - -export interface ExtendedFlexProps extends FlexProps { - [key: string]: string | undefined; + backgroundColor?: FlexBackgroundColor; + theme?: Theme; } diff --git a/HDesign/src/components/InOutItem/InOutItem.stories.tsx b/HDesign/src/components/InOutItem/InOutItem.stories.tsx index 13ea625b5..1805fe0db 100644 --- a/HDesign/src/components/InOutItem/InOutItem.stories.tsx +++ b/HDesign/src/components/InOutItem/InOutItem.stories.tsx @@ -16,12 +16,12 @@ const meta = { }, inOutType: { description: '', - control: {type: 'select', options: ['in', 'out']}, + control: {type: 'select', options: ['IN', 'OUT']}, }, }, args: { names: ['감자', '토다리'], - inOutType: 'out', + inOutType: 'OUT', }, } satisfies Meta<typeof InOutItem>; diff --git a/HDesign/src/components/InOutItem/InOutItem.style.ts b/HDesign/src/components/InOutItem/InOutItem.style.ts index 3137d1908..b3f8eee46 100644 --- a/HDesign/src/components/InOutItem/InOutItem.style.ts +++ b/HDesign/src/components/InOutItem/InOutItem.style.ts @@ -16,7 +16,9 @@ export const prefixStyle = css({ gap: '0.25rem', }); -export const textStyle = (theme: Theme) => +export const textStyle = (theme: Theme, hasDragHandle: boolean) => css({ + paddingLeft: hasDragHandle ? '0' : '0.5rem', + color: theme.colors.black, }); diff --git a/HDesign/src/components/InOutItem/InOutItem.tsx b/HDesign/src/components/InOutItem/InOutItem.tsx index 7cc99622f..9393c5e20 100644 --- a/HDesign/src/components/InOutItem/InOutItem.tsx +++ b/HDesign/src/components/InOutItem/InOutItem.tsx @@ -3,17 +3,23 @@ import React from 'react'; import Text from '@components/Text/Text'; +import Text from '@components/Text/Text'; + import {useTheme} from '@theme/HDesignProvider'; -import IconButton from '../IconButton/IconButton'; import DragHandleItem from '../DragHandleItem/DragHandleItem'; -import {InOutItemProps} from './InOutItem.type'; -import {prefixStyle, textStyle} from './InOutItem.style'; +import {InOutItemProps, InOutType} from './InOutItem.type'; +import {textStyle} from './InOutItem.style'; + +const IN_OUT_TEXT: Record<InOutType, string> = { + IN: '들어옴', + OUT: '나감', +}; export const InOutItem: React.FC<InOutItemProps> = ({ names = [], - inOutType = 'out', + inOutType = 'OUT', hasDragHandle = false, ...htmlProps }: InOutItemProps) => { @@ -22,8 +28,8 @@ export const InOutItem: React.FC<InOutItemProps> = ({ // TODO: (@toari) : 사람 수 많을 때 UX writing 처리 return ( <DragHandleItem {...htmlProps} hasDragHandle={hasDragHandle}> - <Text css={textStyle(theme)} size="captionBold"> - {names.join(', ')} {inOutType === 'out' ? '나감' : '들어옴'} + <Text css={textStyle(theme, hasDragHandle)} size="bodyBold"> + {names.join(', ')} {IN_OUT_TEXT[inOutType]} </Text> </DragHandleItem> ); diff --git a/HDesign/src/components/InOutItem/InOutItem.type.ts b/HDesign/src/components/InOutItem/InOutItem.type.ts index 0a7459ccc..2872e5d55 100644 --- a/HDesign/src/components/InOutItem/InOutItem.type.ts +++ b/HDesign/src/components/InOutItem/InOutItem.type.ts @@ -1,4 +1,4 @@ -export type InOutType = 'in' | 'out'; +export type InOutType = 'IN' | 'OUT'; export interface InOutItemStyleProps {} diff --git a/HDesign/src/components/Input/Input.style.ts b/HDesign/src/components/Input/Input.style.ts index aeedfeb50..50980be64 100644 --- a/HDesign/src/components/Input/Input.style.ts +++ b/HDesign/src/components/Input/Input.style.ts @@ -21,7 +21,7 @@ export const inputBoxStyle = (theme: Theme, inputType: InputType = 'input') => css({ display: 'flex', justifyContent: 'space-between', - marginInline: '1rem', + padding: '0.75rem 1rem', borderRadius: '1rem', backgroundColor: inputBoxBackgroundColorByInputType(theme, inputType), diff --git a/HDesign/src/components/Search/Search.stories.tsx b/HDesign/src/components/Search/Search.stories.tsx index d52f74053..f4cd6d567 100644 --- a/HDesign/src/components/Search/Search.stories.tsx +++ b/HDesign/src/components/Search/Search.stories.tsx @@ -2,6 +2,8 @@ import type {Meta, StoryObj} from '@storybook/react'; import React from 'react'; +import React from 'react'; + import Search from '@components/Search/Search'; const meta = { @@ -24,7 +26,7 @@ const meta = { disabled: false, placeholder: 'placeholder', searchTerms: ['todari', 'cookie'], - setKeyword: (keyword: string) => console.log(keyword), + setState: keyword => console.log(keyword), }, } satisfies Meta<typeof Search>; diff --git a/HDesign/src/components/StepItem/StepItem.tsx b/HDesign/src/components/StepItem/StepItem.tsx index 6f096db12..52e79d863 100644 --- a/HDesign/src/components/StepItem/StepItem.tsx +++ b/HDesign/src/components/StepItem/StepItem.tsx @@ -34,7 +34,7 @@ export const StepItem: React.FC<StepItemCustomProps> = ({ 총액 </Text> <Text css={totalAmountStyle(theme)} size="caption"> - {bills.reduce((acc, prev) => acc + (prev.price ?? 0), 0).toLocaleString('ko-kr')} 원 + {bills.reduce((acc, prev) => acc + (prev.price ?? 0), 0).toLocaleString('ko-kr')}원 </Text> </Flex> </div> diff --git a/HDesign/src/components/Switch/Switch.stories.tsx b/HDesign/src/components/Switch/Switch.stories.tsx index 121e20992..a3558754a 100644 --- a/HDesign/src/components/Switch/Switch.stories.tsx +++ b/HDesign/src/components/Switch/Switch.stories.tsx @@ -14,9 +14,6 @@ const meta = { description: '', control: {type: 'select', options: ['홈', '관리']}, }, - initialValue: { - description: '', - }, values: { description: '', }, @@ -26,7 +23,6 @@ const meta = { }, args: { value: '홈', - initialValue: '홈', values: ['홈', '관리'], onChange: value => alert(`${value} 선택됨`), }, diff --git a/HDesign/src/components/Switch/Switch.tsx b/HDesign/src/components/Switch/Switch.tsx index 17118a6fa..4a1275185 100644 --- a/HDesign/src/components/Switch/Switch.tsx +++ b/HDesign/src/components/Switch/Switch.tsx @@ -3,21 +3,18 @@ import TextButton from '../TextButton/TextButton'; import {switchContainerStyle} from './Switch.style'; import {SwitchProps} from './Switch.type'; -import {useSwitch} from './useSwitch'; - -function Switch({value = '', initialValue, values, onChange}: SwitchProps) { - const {selectedValue, handleClick} = useSwitch({value, initialValue, values, onChange}); +function Switch({value, values, onChange}: SwitchProps) { return ( <div css={switchContainerStyle}> - {values.map((value, index) => ( + {values.map((item, index) => ( <TextButton - key={`${index}_${value}`} - textColor={selectedValue === value ? 'black' : 'gray'} + key={`${index}_${item}`} + textColor={value === item ? 'black' : 'gray'} textSize="bodyBold" - onClick={() => handleClick(index)} + onClick={() => onChange(values[index])} > - {value} + {item} </TextButton> ))} </div> diff --git a/HDesign/src/components/Switch/Switch.type.ts b/HDesign/src/components/Switch/Switch.type.ts index ec73febd0..7e0d31d0f 100644 --- a/HDesign/src/components/Switch/Switch.type.ts +++ b/HDesign/src/components/Switch/Switch.type.ts @@ -1,6 +1,5 @@ export interface SwitchProps { - value?: string; - initialValue?: string; + value: string; values: string[]; onChange: (value: string) => void; } diff --git a/HDesign/src/components/Switch/useSwitch.ts b/HDesign/src/components/Switch/useSwitch.ts deleted file mode 100644 index ecfbb0633..000000000 --- a/HDesign/src/components/Switch/useSwitch.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {useEffect, useState} from 'react'; - -interface UseSwitchProps { - value: string; - initialValue?: string; - values: string[]; - onChange: (value: string) => void; -} - -export const useSwitch = ({value, initialValue, values, onChange}: UseSwitchProps) => { - const [selectedValue, setSelectedValue] = useState(initialValue ?? value); - - useEffect(() => { - setSelectedValue(value); - onChange(value); - }, [value]); - - const handleClick = (index: number) => { - setSelectedValue(values[index]); - onChange(values[index]); - }; - - return {selectedValue, handleClick}; -}; diff --git a/HDesign/src/components/Tab/Tab.stories.tsx b/HDesign/src/components/Tab/Tab.stories.tsx deleted file mode 100644 index e92495e1a..000000000 --- a/HDesign/src/components/Tab/Tab.stories.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import type {Meta, StoryObj} from '@storybook/react'; - -import React from 'react'; - -import Tab from '@components/Tab/Tab'; - -const meta = { - title: 'Components/Tab', - component: Tab, - tags: ['autodocs'], - parameters: { - // layout: 'centered', - }, - args: { - tabs: [ - {label: '전체 지출 내역', content: <div>없지롱</div>}, - {label: '참여자 별 정산', content: <div>있지롱</div>}, - ], - }, -} satisfies Meta<typeof Tab>; - -export default meta; - -type Story = StoryObj<typeof meta>; - -export const Playground: Story = {}; diff --git a/HDesign/src/components/Tab/Tab.tsx b/HDesign/src/components/Tab/Tab.tsx deleted file mode 100644 index 4981b9e92..000000000 --- a/HDesign/src/components/Tab/Tab.tsx +++ /dev/null @@ -1,55 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import {css} from '@emotion/react'; -import React, {useState} from 'react'; - -import Text from '@components/Text/Text'; - -import {useTheme} from '@theme/HDesignProvider'; - -import {tabListStyle, tabTextStyle, tabStyle, tabItemStyle, indicatorStyle} from './Tab.style'; -import {TabsProps} from './Tab.type'; - -const Tab: React.FC<TabsProps> = ({tabs}) => { - const {theme} = useTheme(); - const [activeTabIndex, setActiveTabIndex] = useState(0); - - const isActive = (index: number) => { - return activeTabIndex === index; - }; - - return ( - <section css={tabStyle}> - <ul role="tablist" css={tabListStyle(theme)}> - {tabs.map((tab, index) => ( - <li - key={tab.label} - role="tab" - id={`tab-${tab.label}`} - css={tabItemStyle} - aria-selected={isActive(index)} - onClick={() => setActiveTabIndex(index)} - aria-controls={`tabpanel-${tab.label}`} - > - <Text css={tabTextStyle(theme, isActive(index))} size={isActive(index) ? 'bodyBold' : 'body'}> - {tab.label} - </Text> - </li> - ))} - <div css={indicatorStyle(theme, `${(activeTabIndex * 100) / tabs.length}%`, tabs.length)} /> - </ul> - {tabs.map((tab, index) => ( - <section - key={tab.label} - role="tabpanel" - id={`tabpanel-${tab.label}`} - aria-labelledby={`tab-${tab.label}`} - hidden={activeTabIndex !== index} - > - {tab.content} - </section> - ))} - </section> - ); -}; - -export default Tab; diff --git a/HDesign/src/components/Tab/Tab.type.ts b/HDesign/src/components/Tab/Tab.type.ts deleted file mode 100644 index 80ddd4ef9..000000000 --- a/HDesign/src/components/Tab/Tab.type.ts +++ /dev/null @@ -1,8 +0,0 @@ -export interface TabProps { - label: string; - content: React.ReactNode; -} - -export interface TabsProps { - tabs: TabProps[]; -} diff --git a/HDesign/src/components/Tabs/Tab.tsx b/HDesign/src/components/Tabs/Tab.tsx new file mode 100644 index 000000000..2a79c1b78 --- /dev/null +++ b/HDesign/src/components/Tabs/Tab.tsx @@ -0,0 +1,8 @@ +/** @jsxImportSource @emotion/react */ +import {TabProps} from './Tab.type'; + +const Tab: React.FC<TabProps> = () => { + return <></>; +}; + +export default Tab; diff --git a/HDesign/src/components/Tabs/Tab.type.ts b/HDesign/src/components/Tabs/Tab.type.ts new file mode 100644 index 000000000..6b9e4972e --- /dev/null +++ b/HDesign/src/components/Tabs/Tab.type.ts @@ -0,0 +1,16 @@ +import {FlexProps} from '../Flex/Flex.type'; + +export interface TabProps { + label: string; + content: React.ReactNode; +} + +export interface TabsCustomProps { + children: React.ReactElement<TabProps>[]; +} + +export interface TabsStyleProps { + tabsContainerStyle?: FlexProps; +} + +export type TabsProps = TabsCustomProps & TabsStyleProps; diff --git a/HDesign/src/components/Tabs/Tabs.stories.tsx b/HDesign/src/components/Tabs/Tabs.stories.tsx new file mode 100644 index 000000000..6d03a7406 --- /dev/null +++ b/HDesign/src/components/Tabs/Tabs.stories.tsx @@ -0,0 +1,31 @@ +import type {Meta, StoryObj} from '@storybook/react'; + +import React from 'react'; + +import Tabs from '@/components/Tabs/Tabs'; + +import Tab from './Tab'; + +const meta = { + title: 'Components/Tabs', + component: Tabs, + tags: ['autodocs'], + parameters: { + // layout: 'centered', + }, + args: { + children: [ + <Tab label="전체 지출 내역" content={<div>없지롱</div>} />, + <Tab label="참여자 별 정산" content={<div>있지롱</div>} />, + ], + tabsContainerStyle: { + gap: '0.5rem', + }, + }, +} satisfies Meta<typeof Tabs>; + +export default meta; + +type Story = StoryObj<typeof meta>; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/Tab/Tab.style.ts b/HDesign/src/components/Tabs/Tabs.style.ts similarity index 82% rename from HDesign/src/components/Tab/Tab.style.ts rename to HDesign/src/components/Tabs/Tabs.style.ts index b038fadd1..a4a12f630 100644 --- a/HDesign/src/components/Tab/Tab.style.ts +++ b/HDesign/src/components/Tabs/Tabs.style.ts @@ -2,21 +2,9 @@ import {css} from '@emotion/react'; import {Theme} from '@/theme/theme.type'; -export const tabStyle = css({ - display: 'flex', - flexDirection: 'column', - - width: '100%', -}); - export const tabListStyle = (theme: Theme) => css({ - display: 'flex', position: 'relative', - justifyContent: 'space-between', - alignItems: 'center', - - padding: '0.5rem', backgroundColor: theme.colors.white, diff --git a/HDesign/src/components/Tabs/Tabs.tsx b/HDesign/src/components/Tabs/Tabs.tsx new file mode 100644 index 000000000..0245b5ba7 --- /dev/null +++ b/HDesign/src/components/Tabs/Tabs.tsx @@ -0,0 +1,53 @@ +/** @jsxImportSource @emotion/react */ +import React, {useState} from 'react'; +import {css} from '@emotion/react'; + +import {useTheme} from '@theme/HDesignProvider'; + +import Text from '../Text/Text'; +import Flex from '../Flex/Flex'; + +import {tabListStyle, indicatorStyle, tabItemStyle, tabTextStyle} from './Tabs.style'; +import {TabsProps} from './Tab.type'; + +const Tabs: React.FC<TabsProps> = ({children, tabsContainerStyle}) => { + const {theme} = useTheme(); + const [activeTabIndex, setActiveTabIndex] = useState(0); + + const isActive = (index: number) => activeTabIndex === index; + const tabItemCount = children.length; + + return ( + <Flex flexDirection="column" {...tabsContainerStyle}> + <ul role="tablist" css={tabListStyle(theme)}> + <Flex justifyContent="spaceBetween" alignItems="center" padding="0.5rem"> + {children.map((tabItem, index) => ( + <li + key={tabItem.props.label} + role="tab" + id={`tab-${tabItem.props.label}`} + css={tabItemStyle} + aria-selected={isActive(index)} + onClick={() => setActiveTabIndex(index)} + aria-controls={`tabpanel-${tabItem.props.label}`} + > + <Text css={tabTextStyle(theme, isActive(index))} size={isActive(index) ? 'bodyBold' : 'body'}> + {tabItem.props.label} + </Text> + </li> + ))} + <div css={indicatorStyle(theme, `${(activeTabIndex * 100) / tabItemCount}%`, tabItemCount)} /> + </Flex> + </ul> + <section + role="tabpanel" + id={`tabpanel-${children[activeTabIndex].props.label}`} + aria-labelledby={`tab-${children[activeTabIndex].props.label}}`} + > + {children[activeTabIndex].props.content} + </section> + </Flex> + ); +}; + +export default Tabs; diff --git a/HDesign/src/components/Title/Title.tsx b/HDesign/src/components/Title/Title.tsx index 5901bc350..ee7847a0e 100644 --- a/HDesign/src/components/Title/Title.tsx +++ b/HDesign/src/components/Title/Title.tsx @@ -24,12 +24,12 @@ export const Title: React.FC<TitleProps> = ({title, description, price}: TitlePr {description} </Text> )} - {price && ( + {price !== undefined && ( <div css={priceContainerStyle}> <Text css={priceTitleStyle(theme)} size="caption"> 전체 지출 금액 </Text> - <Text css={priceStyle(theme)}>{price.toLocaleString('ko-kr')} 원</Text> + <Text css={priceStyle(theme)}>{price.toLocaleString('ko-kr')}원</Text> </div> )} </div> diff --git a/HDesign/src/components/TopNav/Back.tsx b/HDesign/src/components/TopNav/Back.tsx new file mode 100644 index 000000000..cfb55e24d --- /dev/null +++ b/HDesign/src/components/TopNav/Back.tsx @@ -0,0 +1,17 @@ +/** @jsxImportSource @emotion/react */ +import React from 'react'; +import {useNavigate} from 'react-router-dom'; + +import TextButton from '@components/TextButton/TextButton'; + +function Back() { + const navigate = useNavigate(); + + return ( + <TextButton onClick={() => navigate(-1)} textSize="bodyBold" textColor="gray"> + 뒤로가기 + </TextButton> + ); +} + +export default Back; diff --git a/HDesign/src/components/TopNav/TopNav.stories.ts b/HDesign/src/components/TopNav/TopNav.stories.ts deleted file mode 100644 index f231e8bd7..000000000 --- a/HDesign/src/components/TopNav/TopNav.stories.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type {Meta, StoryObj} from '@storybook/react'; - -import TopNav from '@components/TopNav/TopNav'; - -import Switch from '../Switch/Switch'; - -const meta = { - title: 'Components/TopNav', - component: TopNav, - tags: ['autodocs'], - parameters: { - layout: 'centered', - }, - argTypes: { - navType: { - description: '', - control: {type: 'select', options: ['back', 'home']}, - }, - }, - args: { - navType: 'back', - }, -} satisfies Meta<typeof TopNav>; - -export default meta; - -type Story = StoryObj<typeof meta>; - -export const Playground: Story = {}; diff --git a/HDesign/src/components/TopNav/TopNav.stories.tsx b/HDesign/src/components/TopNav/TopNav.stories.tsx new file mode 100644 index 000000000..0c96161a5 --- /dev/null +++ b/HDesign/src/components/TopNav/TopNav.stories.tsx @@ -0,0 +1,50 @@ +/** @jsxImportSource @emotion/react */ +import type {Meta, StoryObj} from '@storybook/react'; + +import React from 'react'; +import {reactRouterParameters, withRouter} from 'storybook-addon-react-router-v6'; + +import TopNav from '@components/TopNav/TopNav'; + +import Switch from '../Switch/Switch'; + +import Back from './Back'; + +const meta = { + title: 'Components/TopNav', + component: TopNav, + tags: ['autodocs'], + decorators: [withRouter], + parameters: { + reactRouter: reactRouterParameters({ + location: { + pathParams: { + eventId: '123123', + }, + }, + routing: {path: '/event/:eventId/home'}, + }), + // layout: 'centered', + }, + argTypes: { + children: { + description: '', + control: {type: 'select'}, + options: ['Back', 'Switch', 'Any'], + mapping: { + Back: <Back />, + Switch: <Switch values={['홈', '관리']} value="홈" onChange={value => console.log(value)} />, + Any: <div />, + }, + }, + }, + args: { + children: 'Back', + }, +} satisfies Meta<typeof TopNav>; + +export default meta; + +type Story = StoryObj<typeof meta>; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/TopNav/TopNav.style.ts b/HDesign/src/components/TopNav/TopNav.style.ts index 88910da47..44e7695e7 100644 --- a/HDesign/src/components/TopNav/TopNav.style.ts +++ b/HDesign/src/components/TopNav/TopNav.style.ts @@ -5,3 +5,10 @@ export const topNavStyle = css({ padding: '0 1rem', width: '100%', }); + +export const topNavNonStyle = css({ + display: 'flex', + padding: '0 1rem', + width: '100%', + height: '1.5rem', +}); diff --git a/HDesign/src/components/TopNav/TopNav.tsx b/HDesign/src/components/TopNav/TopNav.tsx index bcfa72260..643cd5e3b 100644 --- a/HDesign/src/components/TopNav/TopNav.tsx +++ b/HDesign/src/components/TopNav/TopNav.tsx @@ -1,26 +1,20 @@ -import {useNavigate} from 'react-router-dom'; +/** @jsxImportSource @emotion/react */ +import React from 'react'; -import TextButton from '../TextButton/TextButton'; -import Switch from '../Switch/Switch'; +import Switch from '@components/Switch/Switch'; -import {topNavStyle} from './TopNav.style'; -import {TopNavProps} from './TopNav.type'; +import {topNavNonStyle, topNavStyle} from './TopNav.style'; +import Back from './Back'; -// TODO: (@todari) navigation으로 인해 storybook 동작하지 않는 오류 해결해야함 -// + 페이지 정하는 것에 따라, navigate 경로 수정해 줘야 함 -function TopNav({navType}: TopNavProps) { - const navigate = useNavigate(); - return ( - <div css={topNavStyle}> - {navType === 'back' ? ( - <TextButton onClick={() => navigate(-1)} textSize="bodyBold" textColor="gray"> - 뒤로가기 - </TextButton> - ) : ( - <Switch values={['홈', '관리']} onChange={() => navigate('./')} /> - )} - </div> +const TopNav: React.FC<React.PropsWithChildren> = ({children}) => { + const hasBack = React.Children.toArray(children).some(child => React.isValidElement(child) && child.type === Back); + const hasSwitch = React.Children.toArray(children).some( + child => React.isValidElement(child) && child.type === Switch, ); -} + + const isExistNav = hasBack || hasSwitch; + + return <div css={isExistNav ? topNavStyle : topNavNonStyle}>{children}</div>; +}; export default TopNav; diff --git a/HDesign/src/components/TopNav/TopNav.type.ts b/HDesign/src/components/TopNav/TopNav.type.ts deleted file mode 100644 index c84e21894..000000000 --- a/HDesign/src/components/TopNav/TopNav.type.ts +++ /dev/null @@ -1,5 +0,0 @@ -type NavType = 'back' | 'home'; - -export interface TopNavProps { - navType: NavType; -} diff --git a/HDesign/src/index.tsx b/HDesign/src/index.tsx index 7f941ad5f..e0b6e6fee 100644 --- a/HDesign/src/index.tsx +++ b/HDesign/src/index.tsx @@ -11,17 +11,21 @@ import Input from '@components/Input/Input'; import Search from '@components/Search/Search'; import StepItem from '@components/StepItem/StepItem'; import Switch from '@components/Switch/Switch'; -import Tab from '@components/Tab/Tab'; +import Tabs from '@/components/Tabs/Tabs'; import Text from '@components/Text/Text'; import TextButton from '@components/TextButton/TextButton'; import Title from '@components/Title/Title'; import TopNav from '@components/TopNav/TopNav'; - import {MainLayout} from '@layouts/MainLayout'; +import {ContentLayout} from '@layouts/ContentLayout'; import {HDesignProvider} from '@theme/HDesignProvider'; +import Tab from './components/Tabs/Tab'; +import Back from './components/TopNav/Back'; + export { + Back, BillItem, BottomSheet, Button, @@ -36,10 +40,12 @@ export { StepItem, Switch, Tab, + Tabs, Text, TextButton, Title, TopNav, MainLayout, + ContentLayout, HDesignProvider, }; diff --git a/HDesign/src/layouts/ContentLayout.tsx b/HDesign/src/layouts/ContentLayout.tsx new file mode 100644 index 000000000..757a580ec --- /dev/null +++ b/HDesign/src/layouts/ContentLayout.tsx @@ -0,0 +1,25 @@ +import {PropsWithChildren} from 'react'; + +import {Flex} from '..'; + +type ContentLayoutBackground = 'white' | 'gray'; + +interface ContentLayoutProps extends PropsWithChildren { + backgroundColor?: ContentLayoutBackground; +} + +export function ContentLayout({backgroundColor, children}: ContentLayoutProps) { + return ( + <Flex + backgroundColor={backgroundColor} + justifyContent="flexStart" + flexDirection="column" + padding="0 1rem" + gap="1rem" + width="100%" + height="100%" + > + {children} + </Flex> + ); +} diff --git a/HDesign/src/layouts/MainLayout.tsx b/HDesign/src/layouts/MainLayout.tsx index 10032b4d8..b64e3c546 100644 --- a/HDesign/src/layouts/MainLayout.tsx +++ b/HDesign/src/layouts/MainLayout.tsx @@ -2,11 +2,23 @@ import {PropsWithChildren} from 'react'; import {Flex} from '..'; -interface MainLayoutInterface extends PropsWithChildren {} +type MainLayoutBackground = 'white' | 'gray'; -export function MainLayout({children}: MainLayoutInterface) { +interface MainLayoutProps extends PropsWithChildren { + backgroundColor?: MainLayoutBackground; +} + +export function MainLayout({backgroundColor, children}: MainLayoutProps) { return ( - <Flex justifyContent="flexStart" flexDirection="column" margin="1rem 0 0 0" gap="1rem" width="100%" height="100%"> + <Flex + backgroundColor={backgroundColor} + justifyContent="flexStart" + flexDirection="column" + padding="1rem 0 0 0" + gap="1rem" + width="100%" + height="100%" + > {children} </Flex> ); diff --git a/HDesign/src/theme/GlobalStyle.ts b/HDesign/src/theme/GlobalStyle.ts index cbef1c8ea..0c1670b07 100644 --- a/HDesign/src/theme/GlobalStyle.ts +++ b/HDesign/src/theme/GlobalStyle.ts @@ -112,4 +112,8 @@ export const GlobalStyle = css` display: flex; justify-content: center; } + + button { + cursor: pointer; + } `; diff --git a/client/src/pages/Main/Main.tsx b/client/src/pages/Main/Main.tsx index dfd7c406e..2a032b5cf 100644 --- a/client/src/pages/Main/Main.tsx +++ b/client/src/pages/Main/Main.tsx @@ -8,6 +8,8 @@ const Main = () => { return ( <MainLayout> + {/* <TopNav navType="back" /> */} + <Title title="행동대장" description="랜딩페이지입니다. 뿌뿌 잠깐만 테스트해볼게요.." /> <TopNav children={<></>} /> <Title title="행동대장" description="랜딩페이지입니다." /> <FixedButton onClick={() => navigate(ROUTER_URLS.eventCreateName)}>행사 생성하기</FixedButton> diff --git a/server/.gitignore b/server/.gitignore deleted file mode 100644 index 671ee930b..000000000 --- a/server/.gitignore +++ /dev/null @@ -1,244 +0,0 @@ -# Created by https://www.toptal.com/developers/gitignore/api/java,intellij,gradle,macos,windows,linux -# Edit at https://www.toptal.com/developers/gitignore?templates=java,intellij,gradle,macos,windows,linux - -### Intellij ### -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/**/usage.statistics.xml -.idea/**/dictionaries -.idea/**/shelf - -# AWS User-specific -.idea/**/aws.xml - -# Generated files -.idea/**/contentModel.xml - -# Sensitive or high-churn files -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml -.idea/**/dbnavigator.xml - -# Gradle -.idea/**/gradle.xml -.idea/**/libraries - -# Gradle and Maven with auto-import -# When using Gradle or Maven with auto-import, you should exclude module files, -# since they will be recreated, and may cause churn. Uncomment if using -# auto-import. -# .idea/artifacts -# .idea/compiler.xml -# .idea/jarRepositories.xml -# .idea/modules.xml -# .idea/*.iml -# .idea/modules -# *.iml -# *.ipr - -# CMake -cmake-build-*/ - -# Mongo Explorer plugin -.idea/**/mongoSettings.xml - -# File-based project format -*.iws - -# IntelliJ -out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Cursive Clojure plugin -.idea/replstate.xml - -# SonarLint plugin -.idea/sonarlint/ - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -# Editor-based Rest Client -.idea/httpRequests - -# Android studio 3.1+ serialized cache file -.idea/caches/build_file_checksums.ser - -### Intellij Patch ### -# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 - -# *.iml -# modules.xml -# .idea/misc.xml -# *.ipr - -# Sonarlint plugin -# https://plugins.jetbrains.com/plugin/7973-sonarlint -.idea/**/sonarlint/ - -# SonarQube Plugin -# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin -.idea/**/sonarIssues.xml - -# Markdown Navigator plugin -# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced -.idea/**/markdown-navigator.xml -.idea/**/markdown-navigator-enh.xml -.idea/**/markdown-navigator/ - -# Cache file creation bug -# See https://youtrack.jetbrains.com/issue/JBR-2257 -.idea/$CACHE_FILE$ - -# CodeStream plugin -# https://plugins.jetbrains.com/plugin/12206-codestream -.idea/codestream.xml - -# Azure Toolkit for IntelliJ plugin -# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij -.idea/**/azureSettings.xml - -### Java ### -# Compiled class file -*.class - -# Log file -*.log - -# BlueJ files -*.ctxt - -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - -# Package Files # -*.jar -*.war -*.nar -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* -replay_pid* - -### Linux ### -*~ - -# temporary files which can be created if a process still has a handle open of a deleted file -.fuse_hidden* - -# KDE directory preferences -.directory - -# Linux trash folder which might appear on any partition or disk -.Trash-* - -# .nfs files are created when an open file is removed but is still being accessed -.nfs* - -### macOS ### -# General -.DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -### macOS Patch ### -# iCloud generated files -*.icloud - -### Windows ### -# Windows thumbnail cache files -Thumbs.db -Thumbs.db:encryptable -ehthumbs.db -ehthumbs_vista.db - -# Dump file -*.stackdump - -# Folder config file -[Dd]esktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -# Windows Installer files -*.cab -*.msi -*.msix -*.msm -*.msp - -# Windows shortcuts -*.lnk - -### Gradle ### -.gradle -**/build/ -!src/**/build/ - -# Ignore Gradle GUI config -gradle-app.setting - -# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) -!gradle-wrapper.jar - -# Avoid ignore Gradle wrappper properties -!gradle-wrapper.properties - -# Cache of project -.gradletasknamecache - -# Eclipse Gradle plugin generated files -# Eclipse Core -.project -# JDT-specific (Eclipse Java Development Tools) -.classpath - -### Gradle Patch ### -# Java heap dump -*.hprof - -# End of https://www.toptal.com/developers/gitignore/api/java,intellij,gradle,macos,windows,linux diff --git a/server/Dockerfile b/server/Dockerfile deleted file mode 100644 index 37e37d237..000000000 --- a/server/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -FROM openjdk:17-jdk-slim - -WORKDIR /app - -COPY /build/libs/*.jar /app/haengdong-0.0.1-SNAPSHOT.jar - -EXPOSE 8080 -ENTRYPOINT ["java"] -CMD ["-Dspring.profiles.active=dev", "-jar", "haengdong-0.0.1-SNAPSHOT.jar"] diff --git a/server/build.gradle b/server/build.gradle deleted file mode 100644 index 26f6ec262..000000000 --- a/server/build.gradle +++ /dev/null @@ -1,40 +0,0 @@ -plugins { - id 'java' - id 'org.springframework.boot' version '3.3.1' - id 'io.spring.dependency-management' version '1.1.5' -} - -group = 'server' -version = '0.0.1-SNAPSHOT' - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(17) - } -} - -configurations { - compileOnly { - extendsFrom annotationProcessor - } -} - -repositories { - mavenCentral() -} - -dependencies { - implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'org.springframework.boot:spring-boot-starter-validation' - compileOnly 'org.projectlombok:lombok' - runtimeOnly 'com.h2database:h2' - runtimeOnly 'com.mysql:mysql-connector-j' - annotationProcessor 'org.projectlombok:lombok' - testImplementation 'org.springframework.boot:spring-boot-starter-test' - testRuntimeOnly 'org.junit.platform:junit-platform-launcher' -} - -tasks.named('test') { - useJUnitPlatform() -} diff --git a/server/gradle/wrapper/gradle-wrapper.jar b/server/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index e6441136f3d4ba8a0da8d277868979cfbc8ad796..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43453 zcma&N1CXTcmMvW9vTb(Rwr$&4wr$(C?dmSu>@vG-+vuvg^_??!{yS%8zW-#zn-LkA z5&1^$^{lnmUON?}LBF8_K|(?T0Ra(xUH{($5eN!MR#ZihR#HxkUPe+_R8Cn`RRs(P z_^*#_XlXmGv7!4;*Y%p4nw?{bNp@UZHv1?Um8r6)Fei3p@ClJn0ECfg1hkeuUU@Or zDaPa;U3fE=3L}DooL;8f;P0ipPt0Z~9P0)lbStMS)ag54=uL9ia-Lm3nh|@(Y?B`; zx_#arJIpXH!U{fbCbI^17}6Ri*H<>OLR%c|^mh8+)*h~K8Z<V--Q23O4&HBVn~<)q zmUaP7+TjluBM%#s1Ki#^GurGElkc7{cc6Skz+1nDVk%wAAQYx1^*wA%KSY>!9)DPf zR2h?lbDZQ`p9P;&DQ4F0sur@TMa!Y}S8irn(%d-gi0*WxxCSk*A?3lGh=gcYN?FGl z7D=Js!i~0=u3rox^e<cs4tSN~YA?c-d185$YFNA$Eq1&U{wh#b^OveuKoBPy0oYZ4 zAY2?B=x8yX9}pVM=cLrvugywt!e@Y3lH)i?7fvT*a`O;c)CJQ>O3i@$0=n{K1lPNU zwmfjRVmLOCRfe=seV&P*1Iq=^i`502keY8Uy-WNPwVNNtJFx?IwA<BCEY82WDKJP< zB^CxjFxi=mg*OyI?K3GoDfk;?-K<Z#JoxhYNeEUf896)l%7gL``44}zn)7|Rf;)SC z_EfJr4I+3i(GiHN`R+vHqf}1wXtH?65<wKlxV1BU(#3XgtH<$Fir3S(7QeRA3)u89 zID&66K{&mq$DsB}s&o?H60{cskfh*hvn8hQW#~Q!qM04QtZvx3JEpqeKWE6|+OZW= z(LB7}flr|t7va%>yR<KG!FYzS$bs7qXcpM&wV@~>PZo2<wCq%CszVO$mosTTuv*Mz zOLoi?e^7B~xS22~QW8Rmnt{(AtL<HGi<_P9`0pH;3)@S9Eg`gt2X<om7C^q}pKX|* zTy3X{nOr-xyt4=Qx1IjrzGb!_SyAv^SZcf;air&-;Ua+)5k0z=#R7@UW%)3oEjGA| zZ#DE3px@h1k7w%|4rVIO=0Aid2A%?nBZrupg^_z5J-$$YKeDZ&q8+k7zccb<dc4D; zz}+UYkl_eUNL3PW+reZ6UUB}=sHp~$z%Q}gZ-#ow+ffQIj|A3`B9LO*6%t@)0PV!x ziJ=9fw_>Wo1+S(xF37LJZ~%i)kpFQ3Fw=mXfd@>%+)RpYQLnr}B~~zoof(JVm^^&f zxKV^+3D3$A1G;qh4gPVjhrC8e(VYUHv#dy^)(RoUFM?o%W-EHxufuWf(l*@-l+7vt z=l`qmR56K~F|v<^Pd*p~1_y^P0P^aPC##d8+HqX4IR1gu+7w#~TBFphJxF)T$2WEa zxa?H&6=Qe7d(#tha?_1uQys2KtHQ{)Qco)qwGjrdNL7thd^G5i8Os)CHqc>iOidS} z%nFEDdm=GXBw=yXe1W-ShHHFb?Cc70+$W~z_+}nAoHFYI1MV1wZegw*0y^tC*s%3h zhD3tN8b=Gv&rj}!SUM6|ajSPp*58KR7MPpI{oAJCtY~JECm)*m_x>AZEu>DFgUcby z1Qaw8lU4jZpQ_$;*7RME+gq1Ky<fW-rh4ehZ;%u960Gt5OF)<y$00S=6tVE=%Pt~( z!&BP&2I%`@>SGG#Wql>aL~k9tLrSO()LWn*q&YxHE<sT^`N@Q|)S3y<ZACaLXO56z zncP$~M5K!npWqz?)C50MMw=XqFtDO!3JHI*t-^8Ga&lGPHX2F0pIGdZ3w5ewE+{kf z-&Ygi?@-h(ADD|ljIBw%VHHf1xuQ~}IeIQ5JqlA4#*Nlvd`IfDYzFa?PB=RCcFpZ4 z|HFmPZM=;^DQ_z<IPz$$+yG(H4803QQAA7vQF7;_gv|AD1bH*R-CP3f<<utDpH)Ht zI@{uO12adp{;132YoKPx?C9{&;MtHdHb*0F0;Z~D42}#*l+WD2u?r>uzmwd1?aAtI zBJ>P=&$=l1efe1CDU;`Fd+_;&wI07?V0aAIgc(<VS*?#8Zt!w88FJrjasA1!6>!{a z0Jg6Y=inXc3^n!U0Atk`iCFIQooHqcWhO(qrieUOW8X(x?(RD}iYDLMjSwffH2~tB z)oDgNBLB^AJBM1M^c5HdRx6fBfka`(LD-qrlh5jqH~);#nw|iyp)()xVYak3;Ybik z0j`(+69aK*B>)e_p%=wu8XC&9e{AO4c~O1U`5X9}?0mrd*m$_EUek{R?DNSh(=br# z#Q61gBzEpmy`$pA<eVn3dnmk^xq`=o2)~2c0ywsuTQsC?1WZZehsJYfK@LQ>*6!87 zSDD+=@fTY7<4A?GLqpA?Pb2z$pbCc4B4zL{BeZ?F-8`s$?>*lXXtn*NC61>|*w7J* z$?!iB{6R-0=KFmyp1nnEmLsA-H0a6l+1uaH^g%c(p{iT&YFrbQ$&PRb8Up#X3@Zsk zD^^&LK~111%cqlP%!_gFNa^dTYT?rhkGl}5=fL{a`UViaXWI$k-UcHJwmaH1s=S$4 z%4)PdWJX;hh5UoK?6aWoyLxX&NhNRqKam7tcOkLh{%j3K^4Mgx1@i|Pi&}<^5>hs5 zm8?uOS>%)NzT(%PjVPGa?X%`N2TQCKbeH2l;cTnHiHppPSJ<7y-yEIiC!P*ikl&!B z%+?>VttCOQM@ShFguHVjxX^?mHX^hSaO_;pnyh^v9EumqSZTi+#f&_Vaija0Q-e*| z7ulQj6Fs*bbmsWp{`auM04gGwsYYdNNZcg|ph0OgD>7O}Asn7^<IivRZw`Wa$`V6) zgX@^QL9j}-Od{q5<J*k0+1U=R5+PCYj(U}4VpX+BjfI~+dttS?HJ6uZSGH#H-twTo zaptG40+PAc$fs*zLFkOfGfc+xGs<T?rLGIA%SU7c%jh!E1SNN~*-`ccW8wo4gv2Sj zhify^C(ygi)uGwqXDLqVbH>Z=eI>`$2*v78;sj-}oMoEj&@)9+ycEOo92xSyY344^ z11Hb8^kdOvbf^GNAK++bYioknrpdN>+u8R?JxG=!2Kd9r=YWCOJYXYuM0cOq^FhEd zBg2puKy__7VT3-r*dG4c62Wgxi52EMCQ`bKgf*#*ou(D4-ZN$+m<X+=`m<r!lO%3T zMp}MJd(WDoQ2&6(LClZxpv<vZPPM3Ngkye2VhB=i|B12g5ouw(%`gbWtRq8~sU|o* z$kQ8Jb~6&{ak;r$7@?#t*q9RfAOj=^uAf1z5Y8`N%M`oM@?!~VqN{g%-u$XR1u1Im zGE&AzFpIcER(5jtCPR%RZ)!+|*rU~jZBiOKdqYjO(%yK3Lz;{##(@QEVo>g&7$u!! z-^<eVk1WtrWdvAzoBMHoB$s2RXJCv}%muyVFFJ``?>+Z%;-3IDwqZ|K=ah85OLwkO zKxNBh+4QHh)u9D?MFtpbl)<T1$eOrb4-+U|WDC2BesgFRlgt`klbeQ^1S`7`r+uZ8 zH&U=geA}Si;CUcKvBA&^@<o1GQ7`{1Y(cCHZv|73JIJOvVwLOMZP%Q|)y@^j2e<+z zWVo=#FL!4XNKS~-_1`gw*qi$0j6P7ym_LTvG>us}9+V!D%w9jfAMYEb>%$A;u)rrI zuBudh;5PN}_6J_}l55P3l_)&RMlH{m!)ai-i$g)&*M`eN$XQMw{v^r@-125^RRCF0 z^2>|DxhQw(mtNEI2Kj(;<s2pnue6O@?^QaAp;Ze6z9nX*w}4h7342+0lU$@;Knnve zqqY2Ci=`)@>KblC7x=JlK$@78`O~>V!`|1Lm-^JR$-5pUANAnb(5}B}JGjBsliK4& zk6y(;$e&h)lh2)L=bvZKbvh@>vLlreBdH8No2>$#%_Wp1U0N7Ank!6$dFSi#xzh|( zRi{U<eziQYNZ-=4ReK3@^LFvNQI~(Pdvp+X@J@g#bd~m0wFc+sW3Xf5tyA3xKp;T3 zy14<o-`F}$ET-DQ;B;yNy?d>w%-4W!{IXZ)fWx@XX6;&(m_F%c6~X8hx=BN1&q}*( zoaNjWabE{oUPb!Bt$eyd#$5j9rItB-h*5JiNi(v^e|XKAj*8(k<5-2$&ZBR5fF|JA z9&m4fbzNQnAU}r8ab>fFV%J0z5awe#UZ|bz?Ur)U9bCIKWEzi2%A+5CLqh?}K4JHi z4vtM;+u<SJ)DEVF_yZnTw01M`(s#^BNx+c|MQ6ogb50Jjul0L;!#OmrYCs)iE)7(t z?%I~O!zVNt#Bf3#O2WXsGz!B}&s@MfyDeaoqqf=GELN3g$+DA`&&GKy(`Ya~A@6vK zn|WZ-+tB`DH^+SjI&K3KekF%-QIP%R{F)inWc~@cEO-=3Or<lm9g9}|`|ky#v{5*; zKA5d<ecC{<o9p<U4UUK$m|+q#@(>PsVz{Lfr;78W78gC;z*yTch~4YkLr&m-7%-xc ztw6Mh2<b07B|^BQBjvq{FXx?kyJ);`+G*=&9PMD`1uf<{+pNnnsIQx~kaB?*5<-7a zqY)GyF_w$>d>_iO<o;tRi5=dcnU&wcur@4T5Z=-$xFUEsp-yX${|jSF|HMDPq3?MS zw;p9zjR`yYJOfJZsK~C-S=JQ?nX{z_y@06JFIpheAo-rOG|5&Gxv)%95gpu@ESfi| z7Auc&hjVL;&81Pc#L`^d9gJb`wEtLVH8q|h{>*$Rd8(-Cr1_V8EO1f*^@wRoSozS) zy1UoC@pruAaC8Z_7~_w4Q6n*&B0AjOmMWa;s<dwKr_&w<X$Z*rmLmKUI3S>Iav&gu z|J5&|{=a@vR!~k-OjKEgPFCzcJ>#A1uL&7xTDn;{X<DkOU(-L87#5hf4{m?aj!I6- zPEt$K07IXK8mI0TYf-jhke2QjQw3v?qN5h0-#Fel0)Krq1f)#^AFsfd|K$I={`Xs9 z{JIr8M>BdeM}V=l3B8fE1--DHjSaxoSjNKEM9|U9#m2<eS=8Og#NOG$&X&%|8sOyg zpZ6&%KPd&uh?v{hRMVvQjUL}gY3)Mk3{XQXF{><3>n{Iuo`r3UZp;>GkT2YBNAh|b z^jTq-hJp(ebZh#Lk8hVBP%qXwv-@vbvoREX$TqRGTgEi$%_F9tZES@z8Bx}$#5eeG zk^UsLBH{bc2VBW)*EdS({yw=?qmevwi?BL6*=12k9zM5gJv1>y#ML4!)iiPzVaH9% zgSImetD@dam~e>{LvVh!phhzpW+iFvWpGT#CVE5TQ40n%F|p(sP5mXxna+Ev7PDwA zamaV4m*^~*xV+&p;W749xhb_X=$|LD;FHuB&JL5?*Y2-oIT(wYY2;73<^#46S~Gx| z^cez%V7x$81}UWqS13Gz80379Rj;6~WdiXWOSsdmzY39L;Hg3MH43o*y8ib<ko|2T z<o~B%-$Y4Q9z_t97c`{g0veSfFt63Osbpe2Osn@<=nrAVk_JfMGt&lMGw9leshc#5 z*hkn0u>NBBH`(av4|u;YPq%{R;IuYow<+GEsf@R?=@tT@!}?#>zIIn0CoyV!hq3mw zHj>OOjfJM3F{RG#6ujzo?y32m^tgSXf@v=J$ELdJ+=5j|=F-~hP$G&}tDZsZE?5rX ztGj`!S>)CFmdkccxM9eGIcGnS2AfK#gXwj%esuIBNJQP1WV~b~+D7PJTmWGTSDrR` zEAu4B8l>NPuhsk5a`rReSya2nfV<T&F{)-N{)9$`9a!^D!-03RDN<TPH!aW46TC4L z>1EK01+G!x8aBdTs3Io$u5!6n6KX%uv@DxAp3F@{4UYg4SWJtQ-W~0MDb|j-$lwVn znAm*Pl!?Ps&3wO=R115RWKb*JKoexo*)uhhHBncEDMSVa_PyA>k{Zm2(wMQ(5NM3# z)jkza|GoWEQo4^s*wE(gHz?Xsg4`}HUAcs42cM1-qq_=+=!Gk^y710j=66(cSWqUe zklbm8+zB_<cF$~mH3zum`PN7rn^cr1XvcjzxFO{ms_482AyMFYi+#o7!*vecrNhft z48z<2q#fIw=ce!MXuptfT4+M8FP&|QfB3H@2)dceSR<*e5@hq<#7<$5tC^!RO8Zi< zd_Wl!>syQv5A2rj!Vbw8;|$@C!vfNmNV!yJ<MblqN@23-5g1<aeoul%Um5K((_QY} ze%_@BuNzay69}2PhmC<;m}2=FevDzrp!V!u4u|#h@B=rfKt+v!U`0k7>IWDQ>{+2x zKjuFX`~~HKG~^6h5FntRpnnHt=D&rq0>IJ9#F0eM)Y-)GpRjiN7gkA8wvnG#K=q{q z9dBn8_~wm4J<3J_vl|9H{7q6u2A!cW{bp#r*-f{gOV^e=8S{nc1DxMHFwuM$;aVI^ zz6A*}m8N-&x8;aunp1w7_vtB*pa+OYBw=TMc6Q<xVqo{NJ3h9-a)s5XuYMqZ=Y{7{ z$O63J`)FM-y*mko#!-UBa!3~eYtX1hjRQY2jMxAx=q5uKNm#uaKIak>K=mbA-|Cf* zvyh8D4LRJImooUaSb7t*fVfih<97Gf@VE0|z>NcBwBQze);Rh!k3K_sfunToZY;f2 z^HmC4KjHRVg+eKYj;PRN^|E0>Gj_zagfRbrki68I^#~6-HaHg3BUW%<xsJq4AotN+ zH6twFV=)FlAbs*F6vGws^==x5Tl0AIbcP{&2yxB=)*u+bvK^L6$Vp}U2{9nj{bK~d zee7tC)@DR<dI`D%cA(%7M9Ui3a)^iG?m=oJO0E^``<|5il2sf1fZHvy=D@e0<I)<l zI!|d{`X3u}lz2(4Vn>+clM1<yhZZgPANro5CwhUb>xQEdPYt_g<2K+z!$>*$9nQ>; zf9Bei{?zY^-e{q_*|W#2rJG`2fy@{%6u0i_VEWTq$*(ZN37|8lFFFt)nCG({r!q#9 z5VK_kkS<W$zJN%xs9<lngf<utn=i|I;bCdr-Lr<EzK)tkE-pYh-fc0wqKz?&U8TTN zh_eAdl<>J3?zOH)OezMT{!YkCuSSn!<oaxO4?NS?VufjhPn>K#-Rhl$uUM(bq*jY? zi1xbMVthJ`E>d>(f3)~fozjg^@eheMF6<)I`oeJYx4*+M&%c9VArn(OM-wp%M<-`x z7sLP1&3^%Nld9Dhm@$3f2}87!quhI<BVn6Upp<cc;cU|)&2W%nk!Ak8tXK8aT!m*5 z^9zmeeS|PCG$hgM&Uh}0wp+#$jK3YCwOT&nx$??=a@_oQemQ~hS6nx6fB5r~bFSPp z`alXuTYys4S5dCK)KDGR@7`I-JV^ewQ_BGM^o>@nwd@3~fZl_3LYW-B?Ia>ui`ELg z&Qfe!7<FViITCBP{rA>m6ze=mZ<W0bN&bq-0D3>`Ia9$z|ARSw|IdMpooY4YiPN8K z4B(ts3p%<w%rbophph+BzYj>2i(Td=<hfIaF6Ll8+9!48Ti=xpXB{FgJbk;>tgEHX z0UQ_>URBtG+-?0E;E7Ld^dyZ;jjw0}XZ(}-QzC6+NN=40oDb2^v!L1g9xRvE#@IBR zO!b-2N7wVfLV;mhEaXQ9XAU+>=XVA6f&T4Z-@AX!leJ8obP^P^wP0aICND?~w&N<u ztispy>ykJ#54x3_@r7IDMdRNy4Hh;h*!u(Ol(#0bJdwEo$5437-UBjQ+j=Ic>Q2z` zJNDf0yO6@mr6y1#n3)s(W|$iE_i8r@Gd@!DWD<Q)gT}bxTg_YpJQ5s|m8}+B)KBN6 zYnlzh>qZ7J&~gAm1#~maIGJ<sH@F<m!Fuh_fvrMbcDJNJ5~Yg;LF}NFN}&Y&LL76S zv)~8W2?_rx`P;4LB-=JqsI{I~4U8DnSSIHWU2rHf%vWsA2-d=78An8z4q|lvgQ2iB zhUUI!H+|C+_qp(Tjzu5usOu}cEoivZK&XA==sh0cD|Eg7eERXx?KwHI=}A9S_rx8S zd)VLh_s!Juqi^!0xv7jH)UdSkEY~N|;QMWvs;HN`dMsdK=Dw2mtAHHcK8_+kS%a_V zGgeQoaMM>1sls^gxL9LLG_Nh<XXk<>U!pTGty!TbhzQnu)I*S^54U6Yu%ZeCg`R>Q zhBv$n5j<?~h)Y%y=zErI?{tl!(JWSDXxco7X8WI-6K;9Z-h&~kIv?$!6<k(g(xee? z53>0v%O_j{QYWG!R9W?5_b&67KB$t}&e2LdMvd(PxN6Ir!H4>PNlerpBL>Zvyy!yw z-SOo8caEpDt(}|gKPBd$qND5#a5nju^O>V&;f890?yEOfkSG^HQVmEbM3Ugzu+UtH zC(INPDdraBN?P%kE;*Ae%Wto&sgw(crfZ#Qy(<4nk;S|hD3j{IQRI6Yq|f^basLY; z-HB&Je%Gg}Jt@={_C{L$!RM;$$|<j7k-g{75e!h)4SlFvEZ*AkqrJI;EWu$Zx+OwM zm{5Yk>iD6vu#3w?v?*;&()uB|I-XqEKqZPS!reW9JkLewLb!70T7n`i!gNtb1%vN- zySZj{8-1>6E%H&=V}LM#xmt`J3XQoaD|@XygXjdZ1+P77-=;=eYpoEQ01B@L*a(uW zrZeZz?HJsw_4g0vhUgkg@VF8<-X$B8pOqCuWAl28uB|@r`19DTUQQsb^pfqB6QtiT z*`_UZ`fT}vtUY#%sq2{rchyfu*pCg;uec2$-$N_xgjZcoumE5vSI{+s@iLWoz^Mf; zuI8kDP{!XY6OP~q5}%1&L}CtfH^N<3o4L@J@zg1-mt{9L`s^z$Vgb|mr{@WiwAqKg zp#t-lhrU>F8o0s1q_9y`gQNf~Vb!F%70f}$>i7o4ho<sjDlFD=G`r<7$U?bJN+x5S z@0&tQ=-XO1uDq(HCa$X)-l<u1!s<!W`30F78UcZaZKc8)G0af1Dsh%OOWh5)q+Q+n zySBnE+3;9^#)U#Gq);&Cu=mtjNpsS~S0yjE@m4{Kq525G&cO_+b-_B$LeXWt_@XTq z`)(;=^RDS@oh5dPjKyGAP?-Dbh507E5zZ=D2_C*6s^HXiA)B3f=65_M+rC&rMIUP6 zi4@u>$`uciNf=xgJ>&!gSt0g;M>*x4-`U)ysFW&Vs^Vk6m%?iuWU+o&m(2Jm26<Ea z?or_^bK_`R)hBTfrBqA3Y^o7$K~Nzo)sh-vT%yWcc1I5wF1nkvk%!X_Vl_MK1IHC= zt}Dt+sOmg0sH-?}kqNB|M_}ZXui7H;?;?xCCSIPSHh8@h^K8WU5X(!3W|>Y(3%TL; zA7T)BP{WS!&xmxNw%J=$MPfn(9*^*TV;$JwRy8Zl*yUZi8jWYF>==j~&S|Xinsb%c z2?B+kpet*muEW7@AzjBA^wAJBY8i|#C{WtO_or&Nj2{=6JTTX05}|H>N2B|Wf!*3_ z7hW*j6p3TvpghEc6-wufFiY!%-GvOx*bZrhZu+7?iSrZL5q9}igiF^*R3%DE4aCHZ zqu>xS8LkW+Auv%z-<1Xs92u23R$nk@Pk}MU5!gT|c7vGlEA%G^2th&Q*zfg%-D^=f z&J_}jskj|Q;73NP4<UD^T*M!yxMr=U!@&!rJfydk7CE7PGb<{)^=nM9Le#FQ=GkV~ z)_A$YPAn35??iNa@`g-wBX><4k*Y%pXPU2Thoqr+5uH1yEYM|VtBPW6lXaetokD0u z9qVek6Q&wk)tFbQ8(^HGf3Wp16gKmr>G;#G(HRBx?F`9AIRboK+;OfHaLJ(P>IP0w zyTbTkx_THEOs%Q&aPrxbZrJlio+hCC_HK<4%f3ZoSAyG7Dn`=X=&h@m*|UYO-4Hq0 z-Bq&+Ie!S##4A6OGoC~>ZW`Y5J)*ouaFl_e9GA*VSL!O_@xGiBw!AF}1{tB)z(w%c zS1Hmrb9OC8>0a_$BzeiN?rkPLc9%&;1CZW*4}CDDNr2gcl_3z+WC15&H1Zc2{o~i) z)LLW=WQ{?ricmC`G1GfJ0Yp4Dy~Ba;j6ZV4r{8xRs`13{dD!xXmr^Aga|C=iSmor% z8hi|pTXH)5Yf&v~exp3o+sY4B^^b*eYkkCYl*T{*=-0HniSA_1F53eCb{x~1k3*`W zr~};p1A`k{1DV9=UPnLDgz{aJH=-LQo<5%+Em!DNN252xwIf*wF_zS^!(XSm(9eoj z=*dXG&n0>)_)N5<wxn0{TP0tnD=JAzVUcIUoR85Xt>oc6v!>-bd(2ragD8O=M|wGW z!xJQS<)u70m&6OmrF0WSsr@I%T*c#Qo#Ha4d3COcX+9}hM5!7JIGF>7<~C(Ear^Sn zm^ZFkV6~Ula6+8S?oOROOA6$C&q&dp`>oR-2Ym3(HT@O7Sd5c~+kjrmM)YmgPH*tL zX+znN>`tv;5eOfX?h{AuX^LK~V#gPCu=)Tigtq9&?7Xh$qN|%A$?V*v=&-2F$zTUv z`C#WyIrChS5|Kgm_GeudCFf;)!WH7FI60j^0o#65o6`w*S7R@)88n$1nrgU(oU0M9 zx+EuMkC>(4j1;m6N<sS-ys^qbJhGY7%0ZoC7dK=j7bGdau`J`{>oGqEkpJYJ?vc|B zOlwT3<tNmX!mXZdsEW2s2`|?DC8;N?2tT*Lfq)F*|4vf>t&UgL!pX_P*6g36`ZXQ; z9~Cv}ANFnJGp(;ZhS(@FT;3e)0)Kp;h^x;$*xZn*k0U6-&Fw<BqOnDKEdld8!Qk{Z zjI1+R_ciEqL3CLOv$+J~YVpzIy`S&V{koIi$Lj}ZFEMN=!rL1?_EjSryIV+OBiiJ- zIqT$oSMA>I=uOGaODdrsp-!K$Ac32^c{+FhI-HkYd5v=`PGsg%6I`4d9Jy)uW0y%) zm&j^9WBAp*P8#kGJUhB!L?a%h$hJgQrx!6KCB_TRo%9{t0J7KW8!o1B!NC)VGLM5! zpZy5Jc{`r{1e(jd%jsG7k%I+m#C<kI0i<ajCqQC!(pKlSsMl7M2N^mP%W`BGKb?hm zBK`pddcg5+WhE#$46+K<Z!1CW-hZdo7hAw13ZUVqwW*}&ujL=eh{m~phuOy=JiBMN z7FaCUn6boJ!M=6PtLN6%cveGkd12|1B{)kEYGTx#IiMN&re0`}NP-_{E-#FxOo3*P zkAXSt{et292KfgGN`AR|C`p{MRpxF-I?+`ZY1Vsv>GS*BPA65ZVW~fLYw0dA-H_}O zrkGFL&P1PG9p2(%Qi<evvBkNEkQkM%A>EWm6x;U-U&I#;Em$nx-_I^wtgw3xUPVVu zqSuKnx&dIT-XT+T10p;yjo1Y)z(x1fb8Dzfn8e yu?e%!_ptzGB|8GrCfu%p?(_ zQccdaaVK$5bz;*rnyK{_SQYM>;aES6Qs^lj9lEs6_J+%nIiuQC*fN;z8md>r_~Mfl zU%p5Dt_YT>gQqfr@`cR!$NWr~+`CZb%dn;WtzrAOI>P_JtsB76<bUr7Lsb65vEd}g z5JhMCmn#UeH#6Cew?bxogM)$x5ed{E)%2nWY5rb@Clvh$(JzQ#!CsQ(2I4QnhDDJ^ zYL%2bf8?`y)Ro=x{(dw<4^)(H^z7~3nfYFh-r7yBBb=l3V8dE-Dr&a%qs<OYcajo2 z(4Nw|k5_OQ@6zHmcIK%waj!yoZT(S1YlEFN?8-_lp9nf>PYe*<%H(y>qx-`Kq!X_; z<{RpAqYhE=L1r*M<cT6p|4(5fVa-WIh|@AphR|cJ1`?N>)gNF3B8r(<%8mo*SR2hu zccLRZwGARt)H<F*kMvg%oJV~29ud_q>lo1euqTyM>^!HK*!Q2P;4UYry<i)yWXzKa zM^_qppY~vnIrhL_!;Z9msXMZTTwR{e`yH5t=HdD1Pni7?LqOpLoX}u5n5RfkGBvQ1 z@cdMeR4T6rp^S~>sje@;(<|$&%vQekbn|0Ruu_Io(w4#%p6ld2Yp7tlA`Y$cciThP zKzNGIMPXX%&Ud0uQh!uQZz|FB`4KGD?3!ND?wQt6!n*f4EmCoJUh&b?;B{|lxs#F- z31~HQ`SF4x$&v00@(P+j1pAaj5!s`)b2RDBp*PB=2IB>oBF!*6vwr7Dp%zpAx*dPr zb@Zjq^XjN?O4QcZ*O+8>)|HlrR>oD*?WQl5ri3R#2?*W6iJ>>kH%KnnME&TT<gNU{ zn$Veg044#l=Z-&wsmEZhnw7IwT7Cd}hiZ%ke)-GzAR-Dt6)8Cb6>@Z<Y-SEE^OC5H z=$M0HjdWR5p?n;s9OTXrEa1eGt}G;Eu)ifSop!$z#6V<>zrHS$Q%LC?n|e>V+D+8D zYc4)QddFz7I8#}y#Wj6>4P%34dZH<AWj}HgE@5&D9Ra@o(Km_Gm}5Zb61p%9mDz1% zya$Vd!_U~pDN*Y5%lo}-K~}4&F)rTjJ7uGyV@~kB-XNrIGRiB=UrNxJtX;JHb(EyQ z{!R%v{vC7m|L3bx6lCRb7!mP~Is!r!q&OXpE5nKnH3@l({o}PrL`o>~OUDb?uP%-E zwjXM(?Sg~1!|wI(RVu<h{6ESg9k500(D<HXwz52OGq(JEKS2CJR}8N&E-#%vhhaRN zL#Q6%yUcel+!a#~g&e7w4$3s62d$Dv;SxCxhT}>xbu)-rH+O=igSho_pDCw(c6b=P zKk4ATlB?bj9+HHlh<_!&z0rx13K3ZrAR8W)!@Y}o`?a*JJsD+twZIv`W)@Y?Amu_u zz``@-e2X}27$i(2=9rvIu5uTUOVhzwu%mNazS|lZb&PT;XE2|B&W1>=B58#*!~D&) zfVmJGg8UdP*fx(>Cj^?yS^zH#o-$Q-*$SnK(ZVFkw+er=>N^7!)FtP3y~Xxnu^nzY zikgB>Nj0%;WOltWIob|}%lo?_C7<``a5hEkx&1ku$|)i>Rh6@3h*`slY=9U}(Ql_< zaNG*J8vb&@zpdhAvv`?{=zDedJ23TD&Zg__snRAH4eh~^oawdYi6A3w8<<tS1{)`* zH!u#2_lf&B)x2)tE$?4|aMAYUFZ{|Se7->Ozh@Kw)<E~4fKYaJ{OS+>#bdktM^GVb zrG08?0bG?|NG+w^&JvD*7LAbjED{_Zkc`3H!My>0u5Q}m!+6VokMLXxl`Mkd=g&Xx z-a>m*#G3SLlhbKB!)tnzfWOBV;u;ftU}S!NdD5+YtOjLg?X}dl>7m^gOpihrf1;PY zvll&>dIuUGs{Q<Ww4SS<E23Sm*si$^C!!snD|AFym<+q$`*o0wokE?J{^g?f3>nd- zwIR3oIrct8Va^Tm0t#(bJD7c$Z7DO9*7NnRZorrSm`b`cxz>OI<bVZt$VQ!oMxCu0 zbb7D5OIXV5Ynn@Y6)HLT=1`a=nh7{ee{vr<=$>C;jSE3DO8`hX955ui`s%||YQtt2 z5DNA&pG-V+4oI2s*x^>-$6J?p=I>C|9wZF8z;VjR??Icg?1w2v5Me+FgAeGGa8(3S z4vg*$>zC-WIVZtJ7}o9{D-7d>zCe|z#<9>CFve-OPAYsneTb^JH!Enaza#j}^mXy1 z+ULn^10<XTm*l1Jg2Z;UvGEN!6Wq%I@OP4p{k`RNRKlKFWPt_of11^Gr%_Mg*mVP3 zm?)&3I719~aYcs)TY&q^$zmQ=xoC++VJH@~YG6>+rWLF6j2>Ya@@Kq?26>AqK{A_| zQKb*~F1>sE*=d?A?W7N2j?L09_7n+H<SF8|SM#pTc9|9|rf1w*m4Y0Vdj643qA#D| z!hJzb_-}IrrhkWr{zk_YC%(c-)UJl6Ma!mcbvj&~#yN-UhH?ZQ3TPq4hTVQ$(?eJ6 zNfJ_K+VJDBXN=l!7{2}lq?-$`fq|e&PEONfZDU<_SM+s2_3$vT_yqV<R&KG=K{zS} zKQF$?mYsg%vV|E_E=a*SL!`7*AeN6GMVDXC59yPgi$F2!7&8e}EyHVLwCm{i%<pN! zdc`SbZK}JQj7?6K&|261iHrsnVjdhxu_l_NKs&yy#;#^%8?Jlg`wcTlNZ3urUtEYd zsFE!K0}Eg39)z+J6mLW)#Kn<ok4*6AAE=n*vh*;TpgGnnM|npykFpO|a0`4#SjP^b z2<JG#Qk^#3FeFS`0eooK9|wEmCcvRKI*~6mamFTd^UW9Eg4!J4N9qz*C$3a#F;Sad zi#o9LaqNG5TsiT<`SDtY^`)zkYx$(C5;&K9#(Zj}HolT_st~#C`VS8q%#q1)HN+hT zz9IjVUdZNIp@;b88oR`~DvQL_zmsBy>Gi{VY;MoTGr_)G9)ot$p!-UY5zZ2Xtbm=t z@dpPSGw<TLTZo~Zyx(+AKWvR~{L4S^5I;5+QT9bcQ-4cC{QnLfRBf&Pov~kv@`W6V zA|h{EGx|7msvR1t`a-jF$JZ>gH=QtIcEulQNI>S-#ifbnO5EWkI;$A|pxJd885oM+ zGZ0_0gDvG8q2xebj+fbCHYfAXuZStH2j~|d^sBAzo46(K8n59+T6rzBwK)^rfPT+B zyIFw)9YC-V^rhtK`!3jrhmW-sTmM+tPH+;nwjL#-SjQPUZ53L@A>y*rt(#M(qsiB2 zx6B)dI}6Wlsw%bJ8h|(lhkJVogQZA&n<jl%@&gd%^X|lsDQwDHEiKLCz}r`kC^h0t z(!vYS%C)Ku?w$ti5R##9jSkNC#5)Juc{8XfEhczdGQy8yNrZL6+d0~%V=N|iF{V)E zLT(gH!$j8Mf(1>{?Vgs6gNSXzuZpEyu*xySy8ro07QZ7Vk1!3tJphN_5V7qOiyK8p z#@jcDD8nmtYi1^l8ml;AF<#IPK?!pqf9D4moYk>d99Im}Jtwj6c#+A;f)CQ*f-hZ< z=p_T86jog%!p)D&5g9taSwYi&e<jP@@Q_fbXtVO&n9{e#)jg+D#~q=hoZ<9PIa)>P z#JuEK%+NULWus;0w32-SYFku#i}d~+{Pkho&^{;RxzP&0!RCm3-9K6`>KZpnzS6?L z^H^V*s!8<>x8bomvD%rh>Zp3>Db%kyin;qtl+jAv8Oo~1g~mqGAC&Qi_wy|xEt2iz zWAJEfTV%cl2Cs<1L&DLRVVH05EDq`pH7Oh7sR<WSzBWU(MxAIA&4v~INVdLKA><BK zwCgTxJU0mM{;1UV<^ZRk0SQNNN(;SRZsH7^EDWVUu%^mFfvW{m5jOQuQWSy`f586I zTj}Z4e5WsvkNmBd`TJdfe=^>`NNkL%wi}8n>IXcO40hp+J+sC!W?!krJf!GJNE8uj zg-y~Ns-<~D?yqbzVRB}G>0A^f0!^N7l=$m0OdZuqA<e9rzV|ixGyk9uS=Vov2_ECA z^Sd0M$B)O&tv@%@UmTb%ngcl58ED9TyFp$y4JjFU+g+9EWUl?am<e#4uCGy9Tmt)z z2Y|kWUahugFHsF<J6o!<?X(Ncsy&Wg9<QLPD}g-`PWGHWDY5P6;<Y+5J1vz2Z|PSy zBN?Q^NkxnWq>OQq<EC8_d&#T2smn`YINd-HF@)Op)pBRHnx+Q|Hsv_BpWAPsT1>Lc zX?AEGr1Ht+inZ-Qiwnl@Z0qukd__a!C*CKuGdy5#nD7VUBM^6OCpxCa2A(X;e0&V4 zM&WR8+wErQ7UIc6LY~Q9x%Sn*Tn>>P`^t&idaOEnOd(Ufw#>NoR^1QdhJ8s`h^|R_ zXX`c5*O~Xdvh%q;7L!_!ohf$NfEBmCde|#uVZvEo>OfEq%+Ns7&_f$OR9xsihRpBb z+cjk8LyDm@U{YN>+r46?nn{7Gh(;WhFw6GAxtcKD+YWV?uge>;+q#Xx4!GpRkVZYu zzsF}1)7$?%s9g9CH=Zs+B%M_)+~*j3L0&Q9u7!|+T`^O{xE6qvAP?XWv9_MrZKdo& z%IyU)$Q95AB4!#hT!_dA>4e@zjOBD*Y=XjtMm)V|+IXzjuM;(l+8aA5#Kaz_$rR6! zj>#&^DidYD$nUY(D$mH`9eb|dtV0b{S>H6FBfq>t5`;OxA4Nn{J(+XihF(stSch<f zIn>e7$es&~N$epi&PDM_N`As;*9D^L==2Q7Z2zD+CiU(|+-kL*VG+&9!Yb3LgPy?A zm<g7T4Wx!m(zMlVE_2jX$1$$5DcfL6>7Z&^qRG_JIxK7-FBzZI3Q<;{`DIxtc48k> zc|0dmX;Z=W$+)qE)~`yn6MdoJ4co;%!`ddy+FV538Y)j(vg}5*k(WK)KWZ3WaOG!8 z!syGn=s{H$odtpqFrT#JGM*utN7B((abXnpDM6w56nhw}OY}0TiTG1#f*VFZr+^-g zbP10`$LPq_;PvrA1XXlyx2uM^mrjTzX}w{yuLo-cOClE8MMk47T25G8M!9Z5ypOSV zAJUBGEg5L2fY)ZGJb^E34R2z<C?_X1)4xsl9%Z|w&L9k!F(V>J?}Vf>{~gB!8=5Z) z9y$>5c)=;o0HeHHSuE4U)#vG&KF|I%-cF6f$~pdYJWk_dD}iOA>iA$O$+4%@>JU08 zS`ep)$XLPJ+n0_i@PkF#ri6T8?ZeAot$6JIYHm&P6EB=BiaNY|aA$W0I+nz*zkz_z zkEru!tj!QUffq%)8y0y`T&`fuus-1p>=^hnBiBqD^hXrPs`PY9tU3m0np~rISY09> z`P3s=-kt_cYcxWd{de@}TwSqg<T-v~${38)1dqT{JCO5}Gk$$yZP*X!5)RaGFqqkZ zeHhqUgXb37$91~LS-3Zi29CKKki0sBTh7unqEK$%FG?oo$Sp>*xVhp;E9zCsnXo6z z?f&Sv^U7n4`xr=mXle94HzOdN!2kB~4=%)u&N!+2;z6UYKUDqi-s6AZ!haB;@&B`? z_TRX0%@suz^TRdCb?!vNJYPY8L_}&07uySH9%W^Tc&1pia6y1q#?*Drf}GjGbPjBS zbOPcUY#*$3sL2x4v_i*Y=N7E<UbOmi3K%)5<dOJui+{^+b*shA_w8&X4_Icv*!}kT zW@BG{C%f{(K^kE?tjU`Led*kAj6wB_3f*UyIEV0T9TyMo4`NS;oA7Ec+71eFa;K|G zCyaKKi1bvX9fTLQ+uAgF*@ZR8fB%|JlT8A-jK$7FMyxW>$mR}J%|GUI(>WEr+28+V z%v5{#e!UF*6~G&%;l*q*$V?&r$Pp^sE^i-0$+RH3ERUUdQ0>rAq2(2QAbG}$y{de( z>{qD~GGuO<V3ijl7+~xmS#nUvH{qF0*%7G(r|}BSXsu}HwrFbXWzcYJouIY*34axA z(n@XsPrv%6;|GSbkH9Og>k559Y@%$?N^1ApVL_a704>8OD%8Y%8B;FCt%AoPu8*D1 zLB5X>b}Syz81pn;xnB}%0FnwazlWfUV<Vu@5P52pgIa+J{M)H4nAC<>)Z-~rZg6~b z6!9J$EcE&sEbzcy?CI~=boWA&eeIa%z(7SE^qgVLz??1Vbc1*aRvc%Mri)AJaAG!p z$X!_9Ds;Zz)f+;%s&d<S0a>RcJt2==P{^j3bf0M=nJd&xwUGlUFn?H=2W(*2I2Gdu zv!gYCwM10aeus)`RIZSrCK=&oKaO_Ry~D1B5!y0R=%!i2*KfXGYX&gNv_u+n9wiR5 z*e$Zjju&ODRW3phN925%S(jL+bCHv6rZtc?!*`1<n2%>TyYXT6%Ju=|X;6D@lq$8T zW{Y|e39ioPez(pBH%k)HzFITXHvnD6hw^lIoUMA;qAJ^CU?top1fo@s7xT13Fvn1H z6JWa-6+FJF#x>~+A;D~;VDs2<i>6>^oH0EI`IYT2iagy23?nyJ==i{g4%HrAf1-*v zK1)~@&(KkwR7TL}L(A@C_S0G;-GMDy=MJn2$FP5s<%wC)4jC5PXoxrQBFZ_k0P<n- z??iM<JF!BTjD>{{s@<jPT1+pTPdk3<izB+}jAtjokIz)aPR$L&4%}45Et}?jz0w{( zC4G}+Nu0D*w=ay`v91hMo+V&V8q(a!`~K-2<yR0H)sK+mcY?TAaSS8F<Q+!pSc;`* z*c@5)+ZpT%-!K3O=Z0(hI8LH7KqK>sz+gX`-!=T8rcB(=7vW}^K6oLWMmp(rwDh}b zwaGGd>yEy6fHv%jM$yJXo5oMAQ>c9j`**}F?MCry;T@47@r?&sKHgVe$MCqk#Z_3S z1GZI~nOEN*P~+UaFGnj{{Jo@16`(qVNtbU>O0Hf57-P>x8Jikp=`s8xWs^dAJ9lCQ z)GFm+=OV%AMVqVATtN@|vp61VVAHRn87}%PC^RAzJ%JngmZTasWBAWsoAqBU+8L8u z4A&Pe?fmTm0?mK-BL9t+{y7o(7jm+RpOhL9Kn<D3v{}Wpv2i&ghEZe;t&DmOA_QYc zM+NIUU}=*bkxOJsLKV3e^oGG8rufTpa8R~7Iki1y+fC(UT;;{l19@qfxO@0^!xMA? z#|<YBZ6;vAb>Y#E&qu^}B6=K_dB}*VlSEiC9fn)+V=J;OnN)Ta5v66ic1rG+dGAJ1 z1%Zb_+!$=tQ~lxQrzv3x#CPb?CekEkA}0MYSgx$Jdd}q8+R=ma$|&1a#)TQ=l$1tQ z=tL9&_^vJ)Pk}EDO-va`UCT1m#Uty1{v^A3P~83_#v^ozH}6*9mIjIr;t3Uv%@VeW zGL6(CwCUp)Jq%G0bIG%?{_*Y#5IHf*5M@wPo6A{$Um++Co$wLC=J1aoG93&T7Ho}P z=mGEPP7Gb<mBTnJH7dKM2CB)0*o-AW2E4i5R+rHU%4A2BTVwOqj4zmJqsb|5^*{DT zv^HFARK6@^_1|vU{>voG!uD$k(H3A$Z))+i{Hy?QHdk>3xSBXR0j!11O^mEe9RH<y zF3MI;^J1vHI9U>mw!pvzv?Ua~2_l2Yh~_!s1qS`|0~0)<BWX>YsbHSz8!mG)WiJE| z2<APmuYD%tKwB@0u<C~CKyaC}XX{?mylzkDSuLMkAoj?zp*zFF7q515SrGD~s}ATn z`Ded41yk>f($6TQtt6L_f~ApQYQKSb=`053LgrQq7G@98#igV>y#i==-nEjQ!XNu9 z<h*hnP2Pol+z>~;mE+gtj4IDDNQJ~JVk5Ux6&LCSFL!y=>79kE9=V}J7tD==Ga+IW zX)r7>VZ9dY=V&}DR))xUoV!u(Z|%3ciQi_2jl}3=$Agc<a_3#EUXJj<z2jVv6VHGT zV^v1FiRwA!kPmt}m$qdr&9#-6{QeZqtM3|tRl$sws3Gy`no`Kj@X-)O(^sv>(`RPb z8kEBpvY>1FGQ9W$n>Cq=DIpski};nE)`p3IUw1Oz0|wxll^)4dq3;CCY@RyJgFgc# zKouFh!`?Xuo{IMz^xi-h=StCis_M7y<P{h0$_I#EukRYag9%BMRXh|%Xl7C<>q$u) z?XHvw*HP0VgR+KR6wI)jEMX|ssqYvSf*_3W8zVTQzD?3>H!#>InzpSO)@SC8q*ii- z%%h}_#0{4JG;Jm`4zg};BPTGkYamx$Xo#O~lBirRY)q=5M45n{GCfV<Kqrcu9<z@R zSE>7h9qwyu1NxOMoP4)jjZMxmT|IQQh0U7C$EbnMN<3)Kk?fFHYq$d|ICu>KbY_hO zTZM+uKHe(cIZfEqyzyYSUBZa8;Fcut-GN!HSA9ius`lt<SmSV9vasBl&hE7ciOunD z?%e1Hl-5B3e+<+8CD{j5U*D3h89nV<zn^0g+t=uRKgZiGu)3h;vu#^y`HqWe_=jGm zW2p}*n<!QH%pQ2EV`&z|LD#BOpj0QS9R5#$q}3&-+@GL4F^wO-bcSo|J^I_{LATPF z2$`fUCOO=XxYVD!<7Yz4te$d-_>NebF46ZX_BbZNU}}ZOm{M2&nAN<H$fJIKS=j8q zwXlN!l^_4>L9@0qvih15(|`S~z}m&h!u4x~(%MAO$jHRWNfuxWF#B)E&g3ghSQ9|> z(MFaLQj)NE0lowyjvg8z0#m6FIuKE9lDO~Glg}nSb7`~^&#(Lw{}GVOS>U)m8bF}x zVjbXljBm<v)#bs=9p`s>34Cs-yM6TVusr+3kYFjr28STT3g056y3cH5Tmge~ASxBj z%|yb>$eF;WgrcOZf569sDZOVwoo%8>XO>XQOX1OyN9I-SQgrm;U;+#3OI(zrWyow3 zk==|{<m8xZ#>lt2xrQ%FIXOTejR>;wv(Pb8u8}BUpx?yd(Abh<shPyABw|Ens8m6@ zIg($GO4)<g4x5icbki?U&2%56@tYd`zRs}Nk6R~4!AjVAihB3r8oDhQ8f)v^r}|(y z4B&Q<ARRqYXKQGAeJa_KHe`)04jUO~B=%q#SUlU@pU?apz0v{Al@s`Cvzo)u;2>6? zsoO3VYWkeLnF43&@*#MQ9-i-d0t*xN-UEyNKeyNMHw|A(k(_6QKO=nKMCxD(W(Yop zsRQ)QeL4X3Lxp^L%wzi2-WVSsf61dqliPUM7srDB?Wm6Lzn0&{*}|IsKQW;02(Y&| zaTKv|`U(pSzuvR6Rduu$wzK_W-Y-7>7s?G$)U}&uK;<>vU}^^ns@Z!p+9?St1s)dG zK%y6xkPyyS1$~&6v{kl?Md6gwM|>mt6Upm>oa8RLD^8T{0?HC!Z>;(Bob7el(DV6x zi`I)$&E&ngwFS@bi4^xFLAn`=fzTC;aimE^!cMI2n@Vo%Ae-ne`RF((&5y6xsjjAZ zVguVoQ?Z9uk$2ON;ersE%PU*xGO@T*;j1BO5#TuZKEf(mB7|g7pcEA=nYJ{s3vlbg zd4-DUlD{*6o%Gc^N!Nptgay>j6E5;3psI+C3Q!1ZIbeCubW%w4pq9)MSDyB{HLm|k zxv-{$$A*pS@csolri$Ge<4VZ}e~78JOL-EVyrbxKra^d{?|NnPp86!q>t<&IP07?Z z^>~IK^k#OEKgRH+LjllZXk7iA>2cfH6+(e&9ku5poo~6y{GC5>(bRK7hwjiurqAiZ zg*DmtgY}v83IjE&AbiWgMyFbaRUPZ{lYiz$U^&Zt2YjG<%m((&_JUbZcfJ22(>bi5 z!J?<7AySj0JZ&<-qXX;mcV!f~>G=sB0KnjWca4}vrtunD^1TrpfeS^4dvFr!65knK zZh`d;*VOkPs4*-9kL>$GP0`<?hW@{z#_gXtp%=2VbN+$~z+M($Vf(dl@)t-*82<$( zHi{FrD1wO9L~*Rc0{A2WU%f?ar(T9V1JpQ?M0Q|&{UES|#Z~k2-mj@z)8Rw^(XeYc zomT(B0EF!##4dQq_*NN<%Bo5)&+gCXSGZo`b>(M!j~B;#x?Ba<KDM~HJ!|Zzy=p2e z8;av`GLw{_*RgO(W|UK-<iDeT!t_x1c=M3%wGk|fDk<e0lLe8-5ga6apKYJD`*a3G zBl?Ps)hDb7X`7bW5S=IHr0Mm?fr|$zCf+gmZUrit$5n+)JZG>~&s6CopvO86oM?-? zOw#dIRc;6A<R&%m3DDJhF+|tb*0Yw8mV{a-bf^E~gh66MdsMHkog<r9`fVIVE+h@O zi)iM`rmA-Fs^c=>6T?B`Qp%^<<Dyu<%Kg0H=lq;E!p&UHzSpD1)q%^v)Y8yQkp>U5 z19x(ywSH$_N+Io!6;e?`tWaM$`=D<O;$E>b!gzx|lQ${DG!zb1Zl&|{kX0y6xvO1o z220r<-oaS^^R2pEyY;=Qllqpmue|5yI~D|iI!IGt@iod{Opz@*ml^w2bNs)p`M(Io z|E;;m*Xpjd9l)4G#KaWfV(t8YUn@A;nK^#xgv=LtnArX|vWQVuw3}B${h+frU2>9^ z!l6)!Uo4`5k`<<;E(ido7M6lKTgWezNLq>U*=uz<KVOwgK<qq^3FEy1LAV}ep3|Zt z>&s=cc$1%>VrAeOoUtA|T6gO4>UNqsdK=NF*8|~*sl&wI=x9-EGiq*aqV!(VVXA57 zw9*o6Ir8Lj1npUXvlevtn(_+^X5rzdR>#(}4YcB9O50q97%rW2me5_L=%ffYPUSRc z!vv?Kv>dH994Qi>U(a<0KF6NH5b16enCp+mw^Hb3Xs1^tThFpz!3QuN#}KBbww`(h z7GO)1olDqy6?T$()R7y%NYx*B0k_2IBiZ14&8|JPFxeMF{vSTxF-Vi3+ZOI=Thq2} zyQgjYY1_7^ZQHh{?P))4+qUiQJLi1&{yE>h?~jU%tjdV0h|FENbM3X(KnJdPKc?~k zh=^Ixv*+smUll!DTWH!jrV*wSh*(mx0o6}1@JExzF(#9FXgmTXVoU+>kDe68N)dkQ zH#_98Zv$}lQwjKL@yBd;U(UD0UCl322=pav<=6g>03{O_3oKTq;9bLFX1ia*lw;#K zOiYDcBJf)82->83N_Y(J7Kr_3lE)hAu;)Q(nUVydv+l+nQ$?|%MWTy`t>{hav<vVD zHx;qQ>FSQloHwiIkGK9YZ79^9?AZo0ZyQlVR#}lF%dn5n%xYksXf8gnBm=wO7g_^! zauQ-bH1Dc@3ItZ-9D_*pH}p!IG7j8A_o<ZOCWxl^<k=*NA9oUpW$0D`yCb}VfC~vb z4IkfiRDM@RHlIGG_SRrrd~6$XYP~2Y^<fekveOOZRCv69S{4_se`>94#~>$LR|TFq zZ-b00*nuw|-5C2lJDCw&8p5N~Z1J&TrcyErds&!l3$eSz%`(*izc;-?HAFD9AHb-| z>)id`QCrzRws^9(#&=pIx9OEf2rmlob8sK&xPCWS+nD~qzU|qG6KwA{zbikcfQrdH z<yJStD<g^`?^d44p$8FFXwD2dL810^xg@~^x$C_H#3NSLs8fBVu~K)3BMKCOp^;|& zKPz+s!|fXFr%*`Dg*#A{!QB-jnah3y4$Pe0L2%RM)706&eqyFTNAO2gMd<bcjBp>+ zQg>O<`K4L8rN7`GJB0*3<3`z({lWe#K!4AZLsI{%z#ja^OpfjU{!{)x0ZH~RB0W5X zTwN^w=|nA!4PEU2=LR05x~}|B&ZP?#pNgDMwD*ajI6oJqv!L81gu=KpqH22avXf0w zX3HjbCI!n9>l046)5rr5&v5ja!xkKK42zmqHzPx$9Nn_MZk`gLeSLgC=LFf;H1O#B zn=8|^1iRrujHfbgA+8i<9jaXc;CQBAmQvMGQPhFec2H1knCK2x!T`e6soyrqCamX% zTQ4dX_E*8so)E*TB$*io{$c6X)~{aWfaqdTh=xEeGvOAN9H&-t5tEE-qso<+C!2>+ zskX51H-H}#X{A75wqFe-J{?o8Bx|>fTBtl&tc<VVc3-U5wTq>bdR|<Uon(X?ZiT<< zWC=zLEjacGDZ|?>132Ztqu5X0i-pisB-z8n71%q%>EF}yy5?z=Ve`}hVh{Drv1YWL zW=%ug_&chF11gDv3D6B)Tz5g<uwqk#dj|RK7gNl@*lm*xHRBk*7MnT4(@7VIDfO0u zB?1X+)GR^0j1A{Q#WUmQX%LN=W?aGzO$5=2@yxjXBzxbGO*{DYkV!aJ!$~-FNzvt; z?r)HU;0!4T-%vWzAiHJ?*-ivIq!#dErMvhpJJ^QyZ5n0qmMn+}I>54H0mDHNj<FD1 z&CIP+ZDDy<;b2`JW=0_p9c4p<zwE30JFgdhO2HQiMRBb%Y9ZJ>uKZ+)CKFk4Z|$RD zfRuKLW`1B>B?*RUfVd0+u8h3r-{@fZ{k)c!93t1b0+Q9vOaRnEn1*IL>5Z4E4dZ!7 ztp4GP-^1d>8~LMeb}bW!(aAnB1tM_*la=Xx)q(I0Y@__Zd$!KYb8T2VBRw%e$iSdZ zkwdMwd}eV9q*;YvrBFTv1>1+}{H!JK2M*C|TNe$ZSA>UHKk);wz$(F$rXVc|sI^lD zV^?_J!3cLM;GJuBMbftbaRUs$;F}HDEDtIeHQ)^EJJ1F9FKJTGH<(Jj`phE6OuvE) zqK^K`;3S{Y#1M@8yRQwH`?kHMq4tHX#rJ>5lY3DM#o@or4&^_xtBC(|JpGTfrbGkA z2Tu+AyT^pHannww!4^!$5?@5v`LYy~T`qs7SYt$JgrY(w%C+IWA;ZkwEF)u5sDvOK zGk;G>Mh&elvXDcV69J_h02l&O;!{$({fng9Rlc3ID#tmB^FIG^w{HLUpF+iB`|<Dd z$~}?*yaE3d3m&(}pR(IuL%&h+j{wz$6(l^GO8O{^N!08Gnw7N>NnX)EH+Nua)3Y(c z&{(nX_ht=QbJ%DzAya}!&uNu!4V0xI)QE$SY__m)SAKcN0P(&JcoK*Lxr@P<Bj^D- zi(H(l^zsWRcIm}YCou&G1we!7IMt1dAI3MKk4-3tybIvwniaUWp=||&s9lB&iptb> zY&P=}&B3*UWNlc|&$Oh{BEqwK2+N2U$4WB7Fd|aIal`FGANUa9E-O)!gV`((ZGCc$ zBJA|FFrl<?%m-}hcKbonJcfriSKJrE#oY4SQUGFcnL~;J2>g~9OBp#f7aHodCe{6= zay$6vN~zj1ddMZ9gQ4p32(7wD?(dE>KA2;SOzXRmPBiBc6g`eOsy+pVcHu=;Yd8@{ zSGgXf@%sKKQz~;!J;|2fC@emm#^_rnO0e<D`xKOl)v&1gxhN0@LroTIseY?HHF`U$ zRCxyayrK2fk|YppMxAKP{J=gze_dhnAkmEFp<%l9vvc1zcx#Lz*hP4TNeag4(W!Be zM4c#}`np`hRl02rJ50(%WD@_u_Qk1TUrpL44g>sEn^QxXgJYd`#FPWOUU5b;9eMAF zZhfiZb|gk8aJIw*YLp4!*(=3l8Cp{(%p?ho22*vN9+5NLV0TTazNY$B5L6UKUrd$n zjbX%#m7&F#U?QNOBXkiiWB*_tk+H?N3`vg;1F-I+83{M2!8<^nydGr5XX}tC!10&e z7D36bLaB56WrjL&HiiMVtpff|K%|*{t*ltt^5ood{FOG0<>k&1h95qPio)<rMG98B zE?gDMmn^Zo(`Ek7uvNsnUgUfUfwFF7?z~>2`eL${YAGIx(b4VN*~nKn6E~SIQUuRH zQ+5zP6jfnP$S0iJ<xI2U>@~t!Ai3o`X7biohl<ds?PbGDArmkAV12ldkGzY{P*80E zF=Wk3w#9|J1dAeV)Rlk?%L=ol!+m5%A|(KP`fR=nD^&iHT@Z5DaZ(w0hqfh|V>i;E zT#yXyl{bojG@-TGZzpdVDXhbmF%F9+-^YSIv|<!(knL3!Z+}F~)r$<ET0f@9KVjok zfvU`%FUbk|yAc)S0rB`JBWTLd7hPAAqP2ltlwee5T}#_Gpbl80w-LA;|BD>MT1l3j zrxOFq>gd2%U}?6}8mIj?M<N%?8n+3Rx8(2-`*c@op88}5-iqw*PHkqnj$k8#t^|g> zc077Zc9fq(-)4+gXv?Az26IO6eV`RAJz8e3)SC7~>%rlzDwySVx*q$ygTR5kW2ds- z!HBgcq0KON9*8Ff$X0wOq$`T7ml(@TF)VeoF}x1OttjuVHn3~sHrMB++}f7f9H%@f z=|kP_?#+fve@{0MlbkC9tyvQ_R?lRdRJ@$qcB(8*jyMyeME5ns6ypVI1Xm*Zr{DuS zZ!1)rQfa89c~;l~VkCiH<d?V{)&8(@3=6jm=fW<)H`CSQ9+iNwDH;4S!Xw4H9nux4 zKNscQ&OV9zHF_+cIJ=X)qIF;(!)}sl`hhO)dHz6nA0^W{a9q1^gzxvh-bS1(N273| zq;PSR{n|+%3`+}9Q7}{mC7k)HXlUhkBKH%A@-sEx!4Mlk=^P1dtF=-lC3U?55B}ez z`Fd)kItC)!X+F!>I|PCBd`S*2RLNQM8!g9L6?n`^evQNEwfO@&JJRme+uopQX0%Jo zgd5G&#&{nX{o?TQwQvF1<^Cg3?2co;_06=~Hcb6~4XWpNFL!WU{+CK;>gH%|BLO<b zgJpht0ltX3sE2RJAUcld5MW}&%<sw};dL~bdZ0?zVg~mRcaNBgUZe;8@DKXRQmlOf zAIhHBNh=}LzcTdUnfgd6#GEx350bi`lb)LaBso2CW!*0Xe!UJNwIWeg)QXy=e3bwZ zIJ8=;u}r&BGoF;ftQ-dJ!kBp#;lHIlNwC)v?OHP&#Mh~B%=jdgWQCSqpANGQEkG%n zM?zk5@$%!-gPc55s943P-Mv1>h7@!hsa(>pNDAmpcuVO-?;Bic17R}^|6@8DahH)G z!EmhsfunLL|3b=M0MeK2vqZ|OqUqS8npxwge$w-4pFVXFq$_EKrZY?BuP@Az@(k`L z`<G71X#W|!P3Z{wEvg5Ob7@MbwprRM&*~yi*+R-9I8&p-;yM=Q)z$bTY1}y<i9f;W zGBCz3n1=6)vV6bV+;GN8E|c1rg49&nk_(FLVA<i_4OxA`vE>ViQBSk`y+YwRT;&W| z2e3UfkCo^uTA4}Qmmtqs+nk<f8_TTXgg$0%V(GO^t)<!()wOU}JKa$=7V(Fd-u5kW zfKQU%n`CZ_1jFoAu|=do)|56^VkbaXtt)NlpAubGIJ@ET@k0K*McoNg@OCSSeKJ`( z*rHh**zg=F3rmZ2ux+4MzedRxj4$W0VqcP)lO*|#;Iw4z!Gidd%|ry%SN>#gNr2W4 zTH%hhErhB)pkXR{B!q5P3-OM+M;qu~f>}IjtF%>w{~K-0*jPVLl?Chz&zIdxp}bjx zStp&Iufr58FTQ36AHU)0+CmvaOpKF;W@sMTFpJ`j;3d)J_$tNQI^c<^1o<49Z(~K> z;EZTBaVT%14(bFw2ob@?JLQ2@(1pCdg3S%E4*dJ}dA*v}_a4_P(a`cHnBFJxNobAv zf&Zl-Yt*lhn-wjZsq<9<PjKts@j|?j*H<KG_l+Ikza{2Tyz(8wgaT$KKCTR@fUFh? z9>v-IsXxAxMZ58C@e0!rzhJ+D@9^3~?~yllY^s$?&oNwyH!#~6x4gUrfxplCvK#!f z$viuszW>MFEcFL?>ux*((!L$;R?xc*myjRIjgnQX7<gW>9@UPD$6Dz0jutM@7h_pq z0Zr)#O<^y_K6jfY^X%A-ip>P%3saX{!v;fxT-*0C_j4=UMH+Xth(XVkVGiiKE#f)q z%Jp=JT)uy{&}Iq2E*xr4YsJ5>w^=#-mRZ4vPXpI6q~1aFwi+lQcimO45V-JXP;>(Q zo={U`{=_JF`EQj87Wf}{Qy35s8r1*9Mxg({CvOt}?Vh9d&(}iI-quvs-rm~P;eRA@ zG5?1HO}puruc@S{YNAF3vmUc2B4!k*yi))<5BQmvd3tr}cIs#9)*AX>t`=~{f#Uz0 z0&Nk!7sSZwJe}=)-R^$0{yeS!V`Dh7w{w5rZ9ir!Z7Cd7dwZcK;BT#V0bzTt>;@Cl z#|#A!-IL6CZ@eHH!CG>OO8!%G8&8t4)Ro@}USB*k>oEUo0LsljsJ-%5Mo^MJF2I8- z#v7a5VdJ-Cd%(a+y6QwTmi+?f8Nxtm{g-+WGL>t;s#epv7ug>inqimZCVm!uT5Pf6 ziEgQt7^%xJf#!aPWbuC_3Nxfb&CFbQy!(8ANp<Dkrrv&eXZOx^ui15L`|GC6Zo9J8 zt4l&YYgkq79`qbC=O@Wu>kWLI4oSnH?Q3f?0k1t$3d+lkQs{~(>06l&v|MpcFsyAv zin6N!-;pggosR*vV=DO(#+}4ps|5$`u<dyVk_IJiOQUOA<$>dE%Kdmp?G7B#y%<bi zGVk-OWo?nx8M9(n3)OkC>H`R|i8skKOd9Xzx8xgR$>Zo2R2Ytktq^w#ul4uicxW#{ zFjG_RNlBroV_n;a7U(KIpcp*{M~e~@>Q#Av90Jc5v%0c>egEdY4v3%|K1XvB{O_8G zkTWLC>OZKf;XguMH2-Pw{BKbFzaY;4v2seZV0>^7Q~d4O=AwaPhP3h|!hw5aqOtT@ z!SNz}$of**Bl3TK209@F=T<Nh*u*7J=P_EEnnD=hbiG0v_)iQwN<!vDIogn=iGRs3 zt_h!RUdkzWHMpc*d}k%tjHimct$!p&AH8pRZ+FJo|9w~+h(n#lp$57vBXGLddx*%@ z5%Aj-8?hH;TIkF9$}Pwu0)KjO*p&uKv6>n1+mgZa8yh(Png%Zd6Mt}^NSjy)etQrF zme*llAW=N_8R*O~d2!apJnF%(JcN??=`$qs3Y+~xs>L9x`0^NIn!8mMRFA_tg`etw z3k{9J<p4JZCS-C}49WuHGGruT=x>Ajnl@ygIiJcNHTy02GMAvBVqEss&t2<2mnw!; zU`J)0>lWiqVqo|ex7!+@0i>B~BSU1A_0w#Ee+2pJx0BFiZ7RDHEvE*ptc9md(B{&+ zKE>TM)+Pd>HEmdJao7U@S>nL(qq*A)#eLOuIfA<xx)>S@j`_sK0UEY6OAJJ-kOrHG zjHx`g!9j*_jRcJ%>CE9K2MVf?BUZKFHY?EpV6ai7sET-tqk=nDFh-(65rhjtlKEY% z@G&cQ<5BKatfdA1FKuB=i>CCC5(|9TMW%K~GbA4}80I5%B}(gck#Wlq@$nO3%@QP_ z8nvPkJFa|znk>V92cA!K1rKtr)skHEJD;k8P|R8RkCq1Rh^&}Evwa4BUJz2f!2=MH zo4j8Y$YL2313}H~F7@J7mh>u%556Hw0VUOz-Un@ZASCL)y8}4XXS`t1AC*^>PLwIc zUQok5PFS=*#)Z!3JZN&eZ6ZDP^-c@StY*t20JhCnbMxXf=LK#;`4KHEqMZ-Ly9KsS zI2VUJGY&PmdbM+iT)zek)<hjl_Ql0Z<Zn_qAb)m1SGqs~RuzvnShAB@_vF{e+592q z$DB!xBIZfcH*9&k=wlV*!)l9TjLaF6{FU=1emb_fuvC;885YA6nM5}UqhPTc%&*tY z3h;oOpGO3Hx+t7EjPYfzaZ}+D=ndS&SDnV=GA-}a=$GiNOi~a`1gJao%JzT9!|NX9 z<CC9{n}y#@=&Y6rk@_w$wqbKs!E-bTFZW}3bqJ;f!@40M^ykqGs3;>#Qc#_i4uH43 z@T5SZBrhNCiK~~esjsO9!qBpaWK<`>!-`b71Y5R<QKZFC;tbrvH*7OQFB+SCa^&~y zposW2PUqn>eXQ4AJU~T<enI;Gq30%Z%SsfHco3Z`w^cm#%0^~onRV&P&#QErx)JwE z+PM!k!qYC}ESrBrHoDQz*X1YmFa#(SZW<AV$!J0LWu4IDbZ2bw=%%Iq9Hg*REoc?; z{E60bn(-sNYKAv{(YDGA5Ne~oOSP*!BJYblyeWN+CVy8q4{fMj;2#8%D!ii%2bR=s z%l;FFHzQ~S|A8UKuFT*34q|LzMc~~o#;)Kw9DtS!bp3JQi_@L6HQjXe7-;AjHEUja z>2Njri1CEp5oKw;Lnm)-Y@Z3sEY}X<ceQi^_CPpPY_VEPYF+%Om#`r)SPUG}UXq2Y zpr9=;`h)oB6MR*Xk2Eh4r7Hb|{>IgSy%xo=uek(kAAH5MsV$V3uTUsoTzxp_rF=tx z<QsYQ(;?5S(qGqiH7>V07vlJNKtJhCu`b}*#m&5LV4TAE&%KtHViDAdv#c^x`J7bg z&N;#I2GkF@SIGht6p-V}`!F_~lCXjl1BdTLIjD2hH$J^YFN`7f{Q?OHPFEM$65^!u zNwkelo*5+$ZT|oQ%o%;rBX$+?xhvjb)SHgNHE_yP%wYkkvXHS{Bf$OiKJ5d1gI0j< zF6N}Aq=(WDo(J{e-uOecxPD>XZ@|u-tgTR<972`q8;&ZD!cep^@B5CaqFz|oU!iFj zU0;<Kr(xN%j}{P50=dczD~4jn(p0D1`)Q|ld@m)3cU?5-DDA%Lq4Vd2?$jcNa3@4} zt0;5Pk0HJXk<P(S=!%ZtD121Ne##d}^nRI9>6fQX&~15E53EW&w1s9gQQ~Zk16X%6 zjG`j0yq}4deX2?Tr(03kg>C(!7a|b9qFI?jcE^Y>-VhudI@&LI6Qa}WQ>4H_!UVyF z((cm&!3gmq@;BD#5P~0;_2qg<pD9=9nXg$TuH}wQh9<MTT}D~YJ$+K3jbd)SV}wix zf+zmLDPNc@nH3C;GngJH(K9z-$bm-ym&hXvg&{t=h}^v&Zpkgh>ZhtJS|>WdtjY=q zLnHH~Fm!cxw|Z?Vw8*~?I$g#9j&uvgm7vPr#&iZgPP~v~BI4jOv;*OQ?jYJtzO<^y z7-#C={r7CO810!^s(MT!@@Vz_SVU)7VBi(e1%1rvS!?PTa}Uv`J!EP3s6Y!xUgM^8 z4f!fq<3Wer_#;u!5ECZ|^c1{|q_lh3m^9|nsMR1#Qm|?4Yp5~|e<cTgyd3~1T9l&* zeQ01<P2U~{V&q4>r2?W^7~cl;_r4WSme_o68J9p03~Hc%X#VcX!xAu%1`R!dfGJCp zV*&m47>s^%Ib0~-2f$6oSgn3jg8m%UA;ArcdcRyM5;}|r;)?a^D*lel5C`V5G=c~k zy*w_&BfySOxE!(~PI$*dwG><<WF75p<o9EVVze~dTW<Z_^0lybcm7u?o5{_6x)ND; zb8GQ#!>+-%KT5p?whOUMA*k<9*gi#T{h3DAxzAPxN&Xws8o9Cp*`PA5>d9*Z-ynV# z9yY*1WR^D8|C%I@vo+d8r^pjJ$>eo|j>XiLWvTWLl(^;JHCsoPgem6PvegHb-OTf| zvTgsHSa;BkbG=(NgPO|CZu9gUCGr$8*EoH2_Z#^BnxF0yM~t`|9ws_xZ8X8iZYqh! zAh;HXJ)3P&)Q0(&F>!LN0g#bdbis-cQxyGn9Qgh`q+~49Fqd2epikEUw9ca<Icy-f zOt40c5j7j)$)tP9?uvS*(MhNoK9DyuR}iw#hq(_Yg;FQNx_fxU*Eu(iTCigNUM7t< z>M%V6WgP)532RMRW}8gNS%V%Hx7apSz}tn@bQy!<=lbhmAH=FsMD?leawbnP5BWM0 z5{)@EEIYMu5;u)!+HQ<i|FmCtfdneL-c-Zq4Plvb%6L#`yCeba4_fn4B8J3*R<jzl zfvYN4K`&;0Sxn>WhQ;D3_Cm_NADNeb-f56}<{41aYq8p4=93d=-=q0Yx#knGYfXVt z+kMxlus}t2T5FEyCN~!}90<Qw*O-2+V!RyNwDJ!D4}()%&9a2ilTUH&u5D!U%eI_q zx}xGi`t`GnBsEW*ontVcR-ikx88LbjAhe<X@Zi_w7Y34lxFFrZ2Q&%wKjDtka2LVK zHc8~1#H%sr<^E7ZD2HEuJ^9vl!WfP^A{M0b1kd0=9ymV8H)Sd)K8ApeV;=DNu1w7T zq3y-B$08B=*qJh`RBSq*hM$V1Wi(wSS$C7SwYBw1{q+D%@|+@4!e&J2mmVQuQ$1nJ zGVp>O_X@@PQpuy;kuGz@bWft%diBTx?d)_xWd_-(!LmVrh**oKg!1CNF&LX4{*j|) zIvjCR0I2UUuuEXh<9}oT_zT#jOrJAHNLFT~Ilh9hGJPI1<5`C-WA{tUYlyMeoy!+U zhA#=p!u1R7DNg9u4|QfED-2TuKI}>p#2P9--z;Bbf4Op*;Q9LCbO&aL2i<0O$ByoI z!9;Ght733FC>Pz>$_mw(F`zU?`m@>gE`9_p*=7o=7av`-&ifU(^)UU`Kg3Kw`h9-1 z6`e6+im=|m2v`pN(2dE%%n8YyQz;#3Q-|x`91z?gj68cMrHl}C25|6(_dIGk*8cA3 zRHB|Nwv{@sP4W+Y<?>ZM)VKI>R<dU=sQkg7!lDS83Q3{+&sk$J+O!cATJ_o5Pb&W_ z)bdtK2>lB`n=Oj~Rzx~M+Khz$N$45rLn6k1nvvD^&HtsMA4`s=MmuOJID@$s8Ph4E zAmSV^+s-z8cfv~Yd(40Sh4JG#F~aB>WFoX7ykaOr3JaJ&Lb49=B8Vk-SQT9%7TYhv z?-Pprt{|=Y5ZQ1?od|A<_IJU93|l4oAfBm?3-wk{O<8ea+`}u%(kub(LFo2zFtd?4 zwpN|2mBNywv+d^y_8#<$r>*5+$wRTCygFLcrwT(qc^n&@9r+}Kd_u@Ithz(6Qb4}A zWo_HdBj#V$VE#l6pD0a=NfB0l^6W^g`vm^sta>Tly?$E&{F?TTX~DsKF~poFfmN%2 z4x`Dc{u{Lkqz&y!33;X}weD}&;7p>xiI&ZUb1H9iD25a(gI|`|;G^NwJPv=1S5e)j z;U;`?n}j<Q^Xq~o28<9wN;wOTm1lpjZMh*aUX(~T_Y3#ZnG~Ye&HG?FC8<&_!tool z+@`jls~3x-4`e?M70izyrpLQDV~@R;Ddqa8ubupC&5hxJ!0Qn2&@6(rv>nY6rA{V^ zxTd{bK)Gi^odL3l989DQlN+Zs39Xe&otGeY(b5>rlIqfc7Ap4}EC?j<{M=hlH{1+d zw|c}}yx88_xQr`{98Z!d^FNH77=u(p-L{W6RvIn40f-BldeF-YD>p6#)(Qzf)lfZj z?3wAMtPPp>vMehkT`3gToPd%|D8~4`5WK{`#+}{L{jR<c)T{dJNa_2~nx}yzR>UMt zrFz+O$C7y8$M&E4@+p+o<?<4i!4ikchlAhrd(TAazwXC#eTotZ4)SbD2SX9vq+(V^ zQt>V5c%uYzbqd2Y%SSgYy#xh4G3hQv>V*BnuKQhBa#=o<cI|?w3{ulWOpdl|%RYTA zSx@6KnTs$R(CM2sHs-QJn!^oj_3M4<ToCw0Dysc#3eTjWBJ-T+adb-$?`_4mF<8?g zSKY1V7KhH!;LK22fSg)B*<uJ7m~6W3CUps0^d9*o2V_Gub>ZB~w{azUB+q%bRe_R^ z>fHBilnRTUfaJ201czL8^~Ix#+qOHSO)A|xWLqOxB$dT2W~)e-r9;bm=;p;RjYahB z*1hegN(VKK+ztr~h1}YP@6cfj{e#|sS`;3tJhIJK=tVJ-*h-5y9n*&cYCSdg#EHE# zSIx=r#qOaLJoVVf6v;(okg6?*L_55atl^W(gm^yjR?$GplNP>BZsBYEf_>wM0Lc;T zhf&gpzOWNxS>m+mN92N0{;4uw`P+9^*|-1~$<g_U{SU`H<rGXK<wL9(P>uXpggj4- z^SFc4`uzj2OwdEVT@}Q`(^EcQ_5(ZtXTql*yGzdS&vrS_w<Vq*ng}zPHZxXbJ~5By z5q!Q1MEDSMNOWX9zY-~b`9@lU+AIe>>~~ra|Nb5abwf}Y!uq6R5f&6g2ge~2p(%c< z@O)cz%%rr4*cRJ5f`n@lvHNk@lE1a*96Kw6lJ~B-XfJW%?&-y?;E&?1AacU@`N`!O z6}V>8^%RZ7SQnZ-<!aS@7Sy5FdEA^NVBSolPfAv!POl_VDW*<OY|VOa1x+Nt4h}kC zF5f5bMcr5zsZz*#rv_qyg5_y;>z$(jsX`amu*5Fj8g!3RTRwK^`2_QH<oOlcTv0T* zq^FmDESBJUwy8>e;_2y_n|6gSaGyPmI#kA0sYV<_qOZc#-2BO%hX)f$s-Z3xlI!ub z^;3ru11DA`4heAu%}HIXo&ctujzE2!6DIGE{?Zs>2}J+p&C$rc7gJC<HidCCr+8PF zWiTVZ>35gxhflorvsb%sGOxpuWhF)dL_&7&Z99=5M0b~Qa;Mo!j&Ti_kXW!86N%n= zSC@6Lw>UQ__F&+&Rzv?gscwAz8IP!n63>SP)^62(HK98nGjLY2*e^OwOq`3O|C92? z;TVhZ2SK%9AGW4ZavTB9?)mUbOoF`V7S=XM;#3EUpR+^oHtdV!GK^nXzCu>tpR|89 zdD{fnvCaN^^LL%amZ^}-E+214g&^56rpdc@yv0b<3<Gcz@z*K79?oK~*UzGlKFJXT z{XOryj|k?!nDS(G1LtLxYD^Cq?c?_!zYn!x^#tLjQ6=Wb!)yrQsQW$6U<7{9%v7a- zv*ocK5QN4V3`xVyd7lYi<tse4LzLtbxdam8l#%xfBL@jXus_3m`H&T(SG4<1{Xtfu zMb*~2c3zevaj8sJ+%2=tK7#q$!xF@Xc_%7Ws0|ayo4RjQhmCcKBx<ij=1uikr$^Pt z9|pP=(@t-<MX5uDFk4~}Y&YCR_($i(L2tZ?=zYb8^M2`}T)&sKMTvyh6Hf2vk#&E} zXFWd3BT@?-Qm?6K=3M(cZ#LOR`xDd$o~J$T>}Ys?)f|fXN4oHf$six)-@<;W&&_kj z-B}M5U*1sb4)77aR=@%I?|Wkn-QJVuA96an25;~!gq(g1@O-5VGo7y&E_srxL6ZfS z*R%$gR}dyONgju*D&?geiSj7SZ@ftyA|<I`YtD1a%3oCr%5@GGkBtN{5mnwPyOw=G z)5mh1d5f2bd0O6v9}uRb?jQWt0Hmbh{Lw~%;q96e<JYrfUt;Ww3`|kuk8YLozMnJA zL-%S-b>}(*Y4KbvU!YLsi1EDQQCnb+-cM=K1io78o!v<D2B&P2)99nqSy|&vmf_z? z=eWr~Nb^z}4FA|*1-U>*);o<<Bb~caN#d%78rHzz&LtUD8*+uiPJdUJ<!gd#RBLsK z$C!13l?*$0KTH~HOk{`~({IY19$^eGtD0+`Ng;Krabee-ZmxY?a!#sR^lIs7X@lqE z)iFHx46*Kc<U3%gK1Qg`N*=%M8g<Qr@DDqezg1<>XwjaQH%)uIP&Zm?)Nfbfn;jIr z)d#!$gOe3QHp}2NBak@yYv3m(CPKkwI|{;d=gi552u?xj9ObCU^DJFQp4t4e1tPzM zvsRIGZ6VF+{6PvqsplMZWhz10YwS={?`~O0Ec$`-!klNUYtzWA^f9m7tkEzCy<_nS z=&<(awFeZvt51>@o_~>PLs05CY)$;}Oo$VDO)?l-{CS1Co=nxjqben*O1BR>#9`0^ zkwk^k-wcLCLGh|XLjdWv0_Hg54B&OzCE^3NCP}~OajK-LuRW53CkV~Su0U>zN%yQP zH8UH#W5P3-!ToO-2k&)}nFe`t+mdqCxxAHgcifup^gKpMObbox9LFK;LP3}0dP-UW z?Zo*^nrQ6*$FtZ(>kLCc2LY*|{!dUn$^RW~m9leoF|@Jy|M5p-G~j%+P0_#orRKf8 zvuu5<*XO!B?1E}-*SY~MOa$6c%2cM+xa8}_8x*aVn~57v&W(0mqN1W`5a7*VN{SUH zXz98DDyCnX2EPl-`Lesf`=AQT%YSDb`$%;(jUT<emmKF_zfZmU9B12q_dyZ<_@h~k zvEq1`Vx6X|zFHC1f>rNen$NPJrlpPDP}prI>Ml!r6bCT;mjsg<oj3+@ct5lWE*J;5 z4E~(;FwK{V8;n^S+p_aly?)G^7&y`S%eK)TJhe8?@}L_b8H};V-{Fr!7~z`5Jn&~y zle5N-{eo+>@X^#&<}CGf0Jt<ps|x+2W>R{Ecwd&)2zuhr#nqdgHj+g2n}GK9CHuwO zk><uMX@X}I+5rrj?NaO6BMSeLuD{-~8R-Gl2xdC9#?M&n3M8$1#r~F<bd_yU6EE{Y z#eCFVb$%8`qmYLY$VN_bTcap4)*3IM0tVFqt0C)EHHU4$9K2ap4$RYn7cYx68f*63 zqjgq9d3s#J0z)IOp-dbsoyDl3q&F;wDIxirPuXzvw6-Mhm_%B8`dB@kd7fLXw-%?$ zoq?`st6r0!H5QKHrVxu9;wFCr4k6@&eG$(7Z2Wi#T=t;uR8LkI#eWjbL4#SB+RR!} zkvLwWmhxM!7BIsi5NeXcxeg6+4^H8NJB5=2mJzA06v|{=fl0X|ig2$)&h*GM&JpHp zr`8`GjG!&l9EyWchuo>oZxy{v<eHuSsx&-tHadS1q^a4f?|RTjYB^sRK14!iW+^lB z!ebp33Hf8OUb(D`D*|G{AftC98wHP4tb?H!)=@9haZJ)F+0;HQc5`Qlnk&U!fz)-9 z%lX#G)XFlYmyE^D)O;h749_^`>cOL)$8-}L^iV<p27<5%t|ClWJe$Rd_|U|Ck(u@6 zTgwrC&(m^cFeKDxIl7TOJH#1Wo==_x;yAITBFJ1z$*I>fJHAGfwN$prHjY<ZwGVKY zZ8+b}fUD+>V0ju}8%jWquw>}_W6j~m<}Jf!G?~r5&Rx)!9JNX!ts#SGe2HzobV5); zpj@&`cNcO&q+%*<%D<T}5E&SDWDa4Lg;*h`<xw$&SGrTg$|CXl_i7+njSd+)yvyz7 z+0<o|PMTJL)R>7za|?m5qlmFK$=MJ_iv{aRs+BGVrs)98BlN^nMr{V_fcl_;<BiuS ztTFCwthZrVHPPZYBIYp#EouQ9MTH{-OaLh9+PRHAG3=cqP}nnZd8AjsX8sR)@*@Na z!0>jkzRju+c-y?gqBC_@J0dFLq-D9@VN&-`R9U;nv$Hg?>$oe4N&Ht$V_(JR3TG^! zzJsbQb<dCovVFFYER#ii{pf+`)Dd4mJA8V_i{)g*7b35$IR9(S%Er0t1yr7X5aERc zeK=jG4aV7X*X+)C@a&31a^^wDy<E&Lu}Ry(`Um&dxXGiHJfU<|q(iByYWWLIS^^>i zFE6-{#9{G{+Z}ww!ycl*7rRdmU#_&|DqPfX3CR1I{Kk;bHwF6jh0opI`UV2W{*|nn zf_Y@%wW6APb&9Rr<YY$Si*BvV^N#m{QYOko?PXQXU(La}0lCv3qWQ$bi`=<yuf89@ zA3M_;xKTP6E^K#?{F`hD*rTDZhZ!h73@a^*&yKH>bEN=PQRBEpM(N1w`81s=(xQj6 z-eO0k9=Al|>Ej|Mw&G`%q8e$2xVz1v4DXAi8G};R$y)ww638Y=9y$ZYFDM$}vzusg zUf+~BPX>(SjA|tgaFZr_e0{)+z9i6G#lgt=F_n$d=beAt0Sa0a7>z-?vcjl3e+W}+ z1&9=|vC=$co}-Zh*%3588G?v&U7%N1<wSL*V~9}~r(eJ^+Xr3`-m(Sj@@;y|({lFw zG+a0jI%A@viPJ_TgyiV93C-_fon>Qf-wNWJ)(v`iO5KHSkC5&g7CrKu8V}uQGcfcz zmBz#Lbqwqy#Z~UzHgOQ;Q-rPxrRNvl(&u6ts4~0=KkeS;zqU<rCYLCOgtuj&A3yvF z)|<)nA^eF$@T!K+ig@JbUkyVVJP%Y)>Rz%!-ERppmd%0v>iRlEf+H$yl{_8TMJzo0 z>n)`On|7=WQdsqhXI?#V{>+~}qt-cQbokEbgwV3QvSP7&hK4R{Z{aGHVS3;+h{|Hz z6$Js}_AJr383c_+6sNR|$qu6dqHXQTc6?(XWPCVZv=)D#6_;D_8P-=zOGEN5&?~8S zl5jQ?NL$c%O)*bOohdNwGIKM#jSAC?BVY={@A#c9GmX0=T(0G}xs`-%f3r=m6-cpK z!%waekyAvm9C3%>sixdZj+I(wQlbB4wv9xKI*T13DYG^T%}zZYJ|0$Oj^YtY+d$V$ zAVudSc-)FMl|54n=N{BnZTM|!>=bhaja?o7s+v1*U$!v!qQ%`T-6fBvmdPbVmro&d zk07TOp*KuxRUSTLRrBj{mjsnF8`d}rMViY8j`jo~Hp$fkv9F_g(jUo#Arp;Xw0M$~ zRIN!B22~$kx;QYmOkos@%|5k)!QypDMVe}1M9tZfkpXKGOxvKXB!=lo`p?|R1l=tA zp(1}c6T3Fwj_CPJwVsYtgeRKg?9?}%oRq0F+r+kdB=bFUdVDRPa;<s*Z4&z%Yqy%U zOeHw$WK*_?C+%QKv}yj&a(!5Ni>E~~>2$w}>O>v=?|e>#(-Lyx?nbg=ckJ#5U6;RT zNvHhXk$<cTrzyFrc-kzJ80|Sr7cPKJYnxQh*Fg9@b51h^!>P}m9wSvFyU3}=7!y?Y z=fg$PbV8d7g25&-jOcs{%}wTDKm>!Vk);&rr;O1nvO0VrU&Q?TtYVU=ir`te8SLlS zKSNmV=+vF|ATGg`4$N1uS|n??f}C_4Sz!f|4Ly8#yTW-FBfvS48Tef|-46C(wE<BN zM?~(EkSJJWr_!W7-HptZRmK`p&C>O_%pPhUC5$-~Y?!0vFZ^Gu`x=m7X99_?C-`|h zfmMM&Y@zdfitA@KPw4Mc(YHcY1)3*1xv<iSQWzdA1>W9V-r4n-9ZuBpFcf{yz+SR{ zo$ZSU_|fgwF~aakGr(9Be`~A|3)B=9`$M-TWKipq-NqRDRQc}ABo*s_5kV%doIX<z zw8f$0lCeVGD0^!OedVm2t32)213YQ46v=o)@UsVzy`KZ%hr__m!jsQbd@}{{Vg1hz z`m2-BpqxgapTIephm4Cik^T6BeWfmt%BA@BRlvqT0ILcR0(vVdxD!}~F3BI!@Yuk* zM2~`l5+!SvcPoj}AC@Q9McO3!2ke!m5VcW3F%a(IA*N@sL73(w3O(3~t5el4Dq{JU z21IfDfV)n^u4cGvvfJlGe~Q~Yzeudy#8j^ja>7LRLRau_gd@Rd_aLFXGSU+U?uAqh z8qusWW<lz^u{++i(BMS0kYpMurHwdx8=v!VDug!+!?SoQ%5#Z9_%%XQ)=}5@(OGY$ z!*NFRMlh?b0mZ-o&{hRY(q#;?AsyI_fTbU3vvt{86Gd^<UxrFKXriAuhLyoz-Rb+| z<1fH@C7QEgQz2VdIb}M#v@~+roe%YIUs5B>cvgQ&wu{|sRXmv?sl=xc<$6AR$+cl& zFNh5q1~kffG{3lDUdvEZu5c(aAG~+64FxdlfwY^*;JSS|m~CJusvi-!$XR`6@XtY2 znDHSz7}_Bx7zGq-^5{stTRy|I@N=>*y$zz>m^}^{d&~h;0kYiq8<^W<E|75Z!A4X; zB0ckyjy2crb1=uu;OnTA+AN(`$!y~N){ZywsrcJ<-RJ-6@#;QH|7$vRI{)h?@p2NX z`N+$B?J?QE9;Pm%%)e)K9b55SBEW5@Zc4|{XhN6&8tG6ODyNFgS%k;enJu!|jBjTn zO3=N;{~$Us+^lM79~#+NVdMuMV*xv4<srsN5l%(Xfx|TFiWsSLu6VKb8+BQX%9T6) zLIA<^s*!o98&YNSoO#lh*yl=4IaXWU@%j6|nHVJL2?PUhARrz8&IkW*Q<47%jpzTI z4gPog-xBcuLB=pm_-|9W&~MFVz_3-f?M6(XIxnIg#$zC^5E`10kVD2)wtP_r+-MVn zDB)nM192c6VQ(1fw5pgW;z9QPF|WVy-Pi3Kqyd;SXdDvK@g#36c@VC&u=_B=n%w}x z9G42<h(@l93n9W)B(s=&>q7Dz0w31ShO^~LUfW6rfitR0(=3;Uue`Y%y@ex#eKPOW zO~V?)M#AeHB2kovn1v=n^D?2{2jhIQd9t|_Q+c|ZFaWt+r&#yrOu-!4pXAJuxM+Cx z*H&>eZ0v8Y`t}8{TV6smOj=__gFC=eah)mZt9gwz>>W$!>b3O;Rm^Ig*POZP8Rl0f zT~o=Nu1J|lO>}xX&#P<uNYpwDdsi81$~7Dv-8cIS(lR52^!TF;6k;WMGV`thcu^6S z@T3rgu^2l&lSgk|u&dqJ2P;_lKd-gsz+E~nyy$zL@l8HyyxzgF#YH#@jXdT>58%Yl z83`HRs5#32Qm9mdCrMlV<JBDhyZ+y^N%S92djDerOElqpRE}K*p`=oMP>|NKNC+Z~ z9OB8xk5HJ>gBLi+m@(pvpw)<om*<*&g*ukIpJ5#uX6#7U*X+*MN|7vZ8*HK)=`Y9r z)#d;zRimk{mmRK`xtmKSn@imtSD%un-#&@aHsi(XFSqmU+t2^tlw;mwe}X*y&#AIH zlv#=?W?e4tr=1o`K<LAS)WBGaORGt!_L??}o8QF5X|ARAXjcw9(=`^ih&uvZ?3o=4 ztCfj-M@ZND9Dnt(PEoh14OzzWaAN5QQ)tU}4*nXvp1HQ^w*zt7KrnA5B`0hYyAdFC zH+>1(OaVJKs*$Ou#@Knd#bk+V@y;YXT?)4eP9E5{J%KGtYinNYJUH9PU3A}66c>Xn zZ{Bn0<;8$WCOAL$^NqTjwM?5d=RHgw3!72WRo0c;+houoUA@HWLZM;^U$&sycWrFd zE7ekt9;kb0`lps{>R(}YnXlyGY}5pPd9zBpgXeJTY_jwaJGSJQC#-KJqmh-;ad&F- z-Y)E>!&`Rz!HtC<wKL>z>%yO<y&s#nmyWumg2@9<En(?C^(|rjP3fstXvL7F_}@s~ zK?}vRELPAe=@^SDzf;4gMIY~6wbR)ERQj~L^17FRR>J|v(u7P*I$jqEY3}(Z-orn4 zlI?CYKNl`6I){#2P1h)y(6?i;^z`N3bxTV%wNvQW+eu|x=kbj~s8rhCR*0H=iGkSj zk2<D*!UmdR0qg)7cV>3lr9kr|p7#qKL=UjgO`@UnvzU)`&fI>1Qs7ubq{@+lK{hH* zvl6eSb9%yngRn^T<;jG1SVa)eA>T^XX=yUS@NCKpk?ovCW1D@!=@kn;l_BrG;hOTC z6K&H{<8K#dI(A+zw-MWxS+~{g$tI7|SfP$EYKxA}LlVO^sT#Oby^grkdZ^^lA}uEF zBSj$weBJG{+Bh@Yffzsw=HyChS(dtLE3i*}Zj@~!_T-Ay7z=B)+*~3|?w`Zd)Co2t zC&4DyB<B`NVJ>!o&YgSw+fJn6`sn$e)29`kUwAc+1MND7YjV%lO;H2}fNy>hD#=gT ze+-aFNpyKIoXY~Vq-}OWPBe?Rfu^{ps8>Xy%42r@RV#*QV~P83jdlFNgkPN=T|Kt7 zV*M`Rh*30&AWlb$;ae130e@}Tqi3zx2^JQHpM>j$6x`#{mu%tZlwx9Gj@Hc92IuY* zarmT|*d0E~vt6<+r?W^UW0&#U&)8B6+1+;k^2|FWBRP9?C4Rk)HAh&=AS8FS|NQaZ z2j!iZ)nbEyg4ZTp-zHwVlfLC~tXIrv(xrP8PAtR{*c;T24ycA-;auWsya-!kF~CWZ zw_uZ|%urXgUbc@x=L=_g@QJ@m#5beS@6W195Hn7>_}z@Xt{DIEA`A&V82bc^#!q8$ zFh?z_Vn|ozJ;NPd^5uu(9tspo8t%&-U9Ckay-s@DnM*R5rtu|4)~e)`z0P-sy?)kc zs_k&J@0&0!q4~%cKL)2l;N*T&0;mqX5T{Qy60%JtKTQZ-xb%KOcgqwJmb%MOOKk7N zgq})R_6**{8A|6H?fO+2`#QU)p$Ei2&nbj6TpLSIT^D$|`TcSeh+)}VMb}LmvZ{O| ze*1IdCt3+yhdYVxcM)Q_V0bIXLgr6~%JS<<&dxIgfL=Vnx4YHuU@I34JXA|+$_S3~ zy~X#gO_X!cSs^XM{yzDGNM>?v(+sF#<0;AH^YrE8smx<36bUsH<L8f?5hvib^(w-z zQO~nQ$dVU0i#a3ki#~Zfn+z)A0X6&+uTO~YY-95PED8rYa#tnOB_5j0D(OiyL`p9s zv+IJ_k!HYz5YcKEc7QF88Nvot?2oM%4aDY1Bzw#ErO+K${;d;Xz}Qst%^Hxe<y|{# z0i<}um0l#qNYBrEHp~^dRc(MW&*nx$<xOZo&ngs@b)HTJL5#EBLw4XB%N{_Unwz1| zV8i$e7agBMpxq^UD+OBzpAA4~Wm`dImRWzuo^(m(ArJer$O=jb))nZ!p#}ai;I|`b zxh~i8wmS;I?uK@A5wM9(c}p9|(M`BOW}{O$gH|yS=WST0IY5xeK;n^|OTOu06VXGL ziLV81^Z>bN#y57K8WEu(`qHvQ6cAZPo=J5C(lSmUCZ57Rj6cx!e^rfaI5%w}unz}4 zoX=nt)FVNV%QDJH`o!u9olLD4O5fl)xp+#RloZlaA92o3x4->?rB4`gS$;<QP`qnB zxyR|2?xCkFimDvX6HOV?^)Ex~)EDlr;3{Zk;-f=p?%7c@-P$(ps9BR^)$rFZsteaA z;pEqzR194rw0JOm6L~PJ9F(nNaRn+j%W1SvOz`}E|6u-%XnRuFO#whbo=$_b&QmEc zz35A#zc{~jeDG0s#(%Oyh`}`Lr28fKNg=;!oXo#n2s2b!wHSqmp4gLtkq~?+{}p*~ zmyPE6L~1+ln$95dm03gaCX?Mx^?0LvGdEce@^Fw=4Li}NJ(PPrnJG8UTM7f;`bHcw z$Z`@wnD>WO{R;Z3>cG3IgFX2EA?PK^M}@%1%A;?f6}s&CV$cIyEr#q5;yHdNZ9h{| z-=dX+a5elJoDo?Eq&Og!nN6A)5yYpnGEp}?=!C-V)(*~z-+<AB{~}$sb=b_3)fww3 z1aC=mU#wAjt*hH!O=_Rq0hO_a&wY#~Xao9@|NW*<bx}+viW;viI*Z+I?~t{%B+v(! zDDr@@d60%bC|=S0vZozViq<m)h@uyR_WM|>?kY1Q7qs#Rsy%hu_60rdbB+QQNr?S1 z?;xtjUv|*E3}HmuNyB9aFL5H~3Ho0UsmuMZELp1a#CA1g`P{-mT?B<X1H9ohvAM^; z+8=gDne1h_tC$>chuLEtK}!QZ=3AWakRu~?f9V~3F;TV`5%9Pcs_$gq&CcU}r8gOO zC2&SWPsSG{&o-LIGTBqp6SLQZPvYKp$$7L4WRRZ0BR$Kf0I0SCFkqveCp@f)o8W)! z$%7D1R`&j7W9Q9CGus_)b%+B#J2G;l*FLz#s$hw{BHS~WNLODV#(!u_2Pe&tMsq={ zdm7>_WecWF#D=?eMjLj=-_z`aHMZ=3_-&E8;ibPmM}61i6J3i<Ry9$0oO(dC+M{8z zs~&fm$9WhF63%!K_Mm6jbUbs_bSm8+)$j`QmCxcnfVz-~LWI0Pvt$(Iiice=m6f#A znKpqTEVc`=3la-JE~IF8T$O7$xw2vGNtATg%;ITCJQ$<SdLX>s*=dKf%HC>=xbj4$ zS|Q-hWQ8T5mWde6h@;mS+?k=89?1FU<%qH9B(l&O>k|u_aD|DY*@~(`_pb|B#rJ&g zR0(~(6<MTX1VH`>8fpUPz6TdS@4JT5MOPrqDh5_H(eX1$P2SQrkvN8sTxwV>l0)Qq z0pzTuvtEAKRDkKGhhv^jk%|HQ1DdF%5oKq5BS>szk-CIke{%js?~%@$uaN3^Uz6Wf z_iyx{bZ(;9y4X&>LPV=L=d+A}7I4GkK0c1Xts{rrW1Q7apHf-))`BgC^0^F(>At1* za@e7{lq%yAkn*NH8Q1{@{lKhRg*^TfGvv!Sn*ed*x@6>M%aaqySxR|oNadYt1mpUZ z6H(<Ni{=BqKRj2FW+}Co`K?u{@WLS%pQm3TU}Q0c616}yg+(R+@sl}k&>rupHYf&Z z29$5g#|0MX#aR6TZ$@eGxxABRKakDYtD%5BmKp;HbG_ZbT+=81E&=XRk6m_3t9PvD zr5Cqy(v?gHcYvYvXkNH@S#Po~q(_7MOuCAB8G$a9BC##gw^5mW16cML=T=ERL7wsk zzNEayTG?mtB=x*wc@ifBCJ|irFVMOvH)AFRW8WE~U()QT=HBCe@s$dA9O!@`zAAT) zaOZ7l6vyR+Nk_OOF!ZlZmjoImKh)dxFbbR~z(cM<ohJsx2;$$S(LMO!JiV@-OGlmm z`NdjOOy9O@m26&M`?ASmTQ{@=-K%#U)U7w<-rclq>hfeX1l7S_`;h|v3gI}<v)x_w zvu)Dq)`qX%>n9$sSQ>+3@AF<e#LTCwgPu=4ybha;DXu-e#IUo*sWeYFrWHoigJs{Q zYu_ff&j$_|OP<X2&rv4d2FV^~F@43}*F8@FN!r^c>Ay9=B_y$)q;Wdl|C-X|VV3w8 z2S#>|5dGA8^9%Bu&fhmVRrTX>Z7{~3V&0UpJNEl0=N32euvDGCJ>#6dUSi&PxFW*s zS`}TB>?}H(T2lxBJ!V#2taV;q%zd6fOr=SGHpoSG*4PDaiG0pdb5`jelVipkEk%FV zThLc@Hc_AL1#D&T4D=w@UezYNJ%0=f3iVRuVL5H?eeZM}4W*bomebEU@e2d`M<~uW zf#Bugwf`VezG|^Qbt6R_=U0}|=k;mIIakz99*>FrsQR{0aQRP6ko?5<7bkDN8evZ& zB@_KqQG?ErKL=1*ZM9_5?Pq%lcS4uLSzN(Mr5=t6xHLS~Ym`UgM@D&VNu8e?_=<G2 z$Y^_uSNUz|Ag`4k$;;4dC>nSFtF$u@hpPSmI4Vo_t&v?>$~K4y(O~Rb*(MFy_igM7 z*~yYUyR6yQgzWnWMUgDov!!g=lInM+=lOmOk4L`O?{i&qxy&D*_qorRbDwj6?)!ef z#JLd7F6Z2I$S0iYI={rZNk*<{HtIl^mx=h>Cim*04K4+Z4IJtd*-)%6XV2(M<qEcY zKpTExU9W`Sp|>CscPiw_a+y*?BKbTS@BZ3AUao^%Zi#PhoY9Vib4N>SE%4>=Jco0v zH_Miey{E;FkdlZSq)e<{`+S3W=*ttvD#hB8w=|2aV*D=yOV}<n%QCtpFj!1iP3=++ zF%bul8RQG~xNUT@7_D%fDp&f9U3+!yV(BF^EJ6M?ggfgy%D_aSJLQh<Q8L9^3Z4lP zSliD?8{L~ZN{}ULe$or4iOcd9fCXx)uXD>(&p%0LbEWH$&@$X3x~CiF-?ejQ*N+-M zc8zT@3iwkdRT2t(XS`d7`tJQAjRmKAhiw{WOqpuvFp`i@Q@!KMhwKgs<K(HF*wpN5 zv(vj1XA8yT@r9sbul0J^6}T8DTrg3?UvaTK(_8@BG(vOS@R#A};jf~t=|7FM{G%;V z$moCx(glgj5-;%1QM|u%2d3FX97|2!-{zNf(~wZQL8&V6ON(xoE>A}%@sw8Xo5Y=F zhRJZg)O4uqNWj?V&&vth*H#je6T}}p_<>!Dr#89q@uSjWv~JuW(>FqoJ5^ho0%K?E z9?x_Q;kmcsQ@5=}z@tdljMSt9-Z3xn$k)kEjK|qXS>EfuDmu(Z8|(W?g<kN}okBu| z`906+8rq=5w?nFA6VC1#eQVZ_=+&soKuCq9J4-B?5ajOsO<ZqBE?J2XT_J8fPV98+ zk#wtSBTro80%$s5KaeCr*oviwvkprv-mw0v@x!YSCMmDCbzwIduaRkq+nkD$>Y6-l z@R_#M8=vxKMAoi&PwnaIYw2COJM@atcgfr=zK1bvjW?9B`-+Voe$Q+H$j!1$Tjn+* z&LY<%)L@;zhnJlB^Og6I<R<r5yYZK!bg%i+z^Gb9&z&*Z#pVBay5jNKYESI$cqK!; zs%j&*N?LE3ILkbKV_0UUpL<A`zeQtv+?k$&h|~*OX&e)^SV^abQ&PMGXtX3fI2kT= z2Y%RbH`bf;|K;F8Mxo)Ov25Y*lHOz#D>&BOR-m?{IW;tyYC%FZ!&Z>kGjHJ6cqM-F z&19n+e1=9AH1VrVeHrIzqlC`w9=*zfmrerF?JMzO&|Mmv;!4DKc(sp+jy^Dx?(8>1 zH&yS_4yL7m&GWX~mdfgH*AB4<e8V;o9`b8>{CKo;+egw=PrvkTaoBU+P-4u?E|&!c z)DKc;>$$B6u*Zr1SjUh<mc1^2+c=@@6(J4|#?}T_|M2b62=4`4F-ba1m43BpL!aCj zR^w2TEDEd$X7pi$++6T@mH_M(zN#-+gi}U5eaDqd^tUG_>2)FeuWLWHl5TH(UHWkf zLs>7px!c5n;rbe^lO@ql<wf#W%s8knI~Th~JR_Kl+2&@Zoorl!op+Ba_ZYj2yD(^E z$}7%1B7{$MlPHueM^5x<Vc5^Pd5$8yYQ@u;!UngDNs9O`zY)-uu_X-;n9-+TuAb`^ z<H1e|G%#k-<p?8qbT%m<kMd#1>YLzlDVp(z?6r<WUtyWnlD^G9B?_Ur{&KCOuHNMq zk|B^K_<0Q-9-+@;d#BY&2k-R$to<44{eG#pW>PZel=YB)Uv&n!2{+Mb$-vQl=xKw( zve&>xYx+jW_NJh!FV||r?;hdP<!CWxpcsZKiv4>*jOXYcLCp>DOtJ?2S^)DkM{{Eb zS$!L$e_o0(^}n3tA1R3-$SNvgBq;DOEo}fNc|tB%%#g4RA3{|euq)p+xd3I8^4E&m zFrD%}nvG^HUAIKe9_{tXB;tl|G<%>yk6R;8L2)KUJw4yHJXUO<O#J#etA!EQr#Ixj zZuFu$GT+Wpqx#)|V^@Cm`sHrRN~=Je%6V#~5_a6U7SazOW-GgiQtB4%%~2(B0iBsg z;PpJsF|+l@`Wy@y_OtfS`JgrB)rNO1MTjsxeQ7|k!FQ^3n6kbM;^~mT&4KxW*m77y zq%{h&JwttX7mQ1|xDfr$rzHoYHzjn|^DmxVimK9<IM)^a;|9O2LO78(*WR_|D40bM z4}thc%eqOsDqUE<D1~O4evp0zw~wzT!F>PM>(-+jxq4R;z8H#>rnJy*)8N+$wA$^F z<U&lTYAkA<S9x1+2s?lu2|Zd2nj#EvZB!v_&9eAD+8*)ghmbT+{)~_^Px6pMeOz2X zv~Wjk&YGtROVvA~E^msuyea-{C!TM*WVVa4lhy%2Gi&UvdDpYWzNapW2o<z2pU37x zeudIr){wxOzdWU}R?Ue;nbpX4`c>N+H*3t)eFEgxLw+Nw3};4WV$qj&_D`%ADV2%r zJCPCo%{=z7;`F98(us5JnT(G@sKTZ^;2FVitXyLe-S5(hV&Ium+1pIUB(CZ#h|g)u zSLJJ<@HgrDiA-}V_6B^x1>c9B6%~847JkQ!^KLZ2skm;q*edo;UA)~?SghG8;QbHh z_6M;ouo_1rq9=x$<`Y@EA{C%6-pEV}B(1#sDoe_e1s3^Y>n#1Sw;N|}8D|s|VPd+g z-_$QhCz`vLxxrVMx3ape1xu3*wjx=yKSlM~nFgkNWb4?DDr*!?U)L_VeffF<+!j|b zZ$Wn2$TDv3C3V@BHpSgv3JUif8%hk%OsGZ=OxH@8&4`bbf$`aAMchl^qN>Eyu3JH} z9-S!x8-s4fE=lad%Pkp8hAs~u?|uRnL48O|;<hL9ZDZTaoVqCgAV4_fXA_B>*DEU! zuS0{cpk%1E0nc__2%;apFsTm0bKtd&A0~S3Cj^?72-*Owk3V!ZG*PswDfS~}2<8le z5+W^`Y(&R)yVF*tU_s!XMcJS`;<i5$MCe|U*GT!0%*LADX`D^%6_<=D#Ru0`TRN8+ zm@tIK)49`32a<@shitOU#x<QU%nW!IzfjK>(Tr`J0%>p=Z&InR%D3@KEzzI+-2)HK zuoNZ&o=wUC&+*?ofPb0a(E6(<2Amd6%uSu_^-<1?hsxs~0K5^f(L<W1_uUGAdyXWF z-9E^}>sGqgEF^+0_H=uNk9S0bb!|O8d?m5gQjUKevPaO+*VfSn^2892K~%crWM8+6 z25@V?Y@J<9w%@NXh-2!}SK_(X)O4AM1-WTg>sj1{lj5@=q&dxE^9xng1_z9w9DK>| z6Iybcd0<ba%T-PM@iR4f+hWNy2(Dh#%r^4ZjOOcYUhl?lcc*@SuVYF<0NRX~sTl15 z&yX+gisvpMdp($7GpQ}~BtfayBnqkt65sVAS)H#))Ya=X_9qRpsELVk)K-Umx|Q>e zy<csGv$iOY<#zt!tLyihB^h0nm-w?)HRS0&_TFyZkN{(*U!r-+J#Pt@VJw|c&+Ad7 zGuhURv<S1E^2YPq{$<>i;Ew!KBRIfGPGytQ6}z}MeXCfLY0?9%RiyagSp_D1?N&c{ zyo>VbJ4Gy`@Fv+5cKgUgs~na$>BV{*em7PU3%lloy_aEovR+J7TfQKh8BJXyL6<F; zULuFu;b(C;CC(l^>|P8un-Jnq(ghd!_HEOh$zlv2$~y3krgeH;9zC}V3<xe_B^^Vb z>f`uDtW(%mT#944DQa~^8ZI+zAUu4U(j0YcDfKR$bK#gvn_{JZ<YX};laf~yTsdEA zA~Ra?VD!R`MyGN9;7}SV*B=q$h>>|gZ5+)u?T$w<UlM8Es^_5l0fa>7Q%F^;!Wk?G z(le7r!ufT*cxS}PR6hIVtXa)i`d$-_1KkyBU>qmgz-=T};uxx&sKgv48akIWQ89F{ z0<y9Cbjk%^#=J+qPnsNw%*mP1XLirQj9jh94t22gxgVWwR*I>XiY?WM^~;|T8zBOr zs#zuOONzH?svv*jokd5SK8wG>+yMC)LYL|vLqm^PMHcT=`}V$=nIRHe2?h)8WQa6O zPAU}d`1y(>kZiP~Gr=mtJLMu`i<2CspL|q2DqAgAD^7*$xzM`PU4^ga`ilE134XBQ z99P(LhHU@7qvl9Yzg$M`+dlS=x^(m-_3t|h>S}E0bcFMn=C|KamQ)=w2^e)35p`zY zRV8X?d;s^>Cof2SPR&nP3E+-LCkS0J$H!eh8~k0qo$}00b=7!H_I2O+Ro@3O$nPdm ztmbOO^B+IHzQ5w>@@@J4cKw5&^_w6s!s=H%&byAbUtczPQ7}wfTqxxtQNfn*u73Qw zGuWsrky_ajPx-5`R<)6xHf>C(oqGf_Fw|-U*GfS?xLML$kv;h_pZ@Kk$y0X(S+K80 z6^|z)*`5VUkawg}=z`S;VhZhxyDfrE0$<offD>(PMurAxl~<>lfZa>JZ288ULK7D` zl9|#L^JL}Y$j*j`0-K6kH#?bRmg#5L3iB4Z)%iF@SqT+Lp|{i`m%R-|ZE94Np7Pa5 zCqC^V3}B(FR340pmF*qaa}M}+h6}mqE~7Sh!9bDv9YRT|>vBNAqv09zXHMlcuhKD| zcjjA(b*XCIwJ33?CB!+;{)vX@9xns_b-VO{i0y?}{!sdXj1GM8+$#v>W7nw;+O_9B z_{4L;C6ol?(?W0<6taGEn1^uG=?Q3i29sE`RfYCaV$3DKc_;?HsL?D_fSYg}SuO5U zOB_f4^vZ_x%o`5|C@9C5+o=mFy@au{s)sKw!UgC&L35aH(sgDxRE2De%(%OT=VUdN ziVLEmdOvJ&5*tCMKRyXctCwQu_RH%;m<lO9)YlolKp~SHA~$RD@rJEPJ4LfFabjtz zzIU?%C*Qz8oJB~DbsOtV|5q`38L}^8Uq{e{^Ki<?YLnvYT2b=9GoWdOL!w)E5Yy?N zCPB}zb-LW~opI;Pm$>*$YK&m;jtbdH#Ak~13T1^f89tn`A%QEHWs~jnY~E}p_Z$XC z=?YXLCkzVSK+Id`xZYTegb@W8_baLt-Fq`Tv|=)JPbFsKRm)4UW;yT+J`<<s6L^~# zDKX^stn#n?Mc#=>)%#ue9DPOkje)YF2fsCilK9MIIK>p*`fkoD5nGfmLwt)!KOT+> zOFq*VZktDDyM3P5UOg`~XL#cbzC}eL%qMB=Q5$d89MKuN<r)TznqqP**!jJ?cnTT2 zaaf?rvaC;><?H&|zm@ni*?D9zRWNdd5|h7<r<^y7j=M<<S|!iYxdgG*6u6u?mWfD3 zB)<Dfkbae`fO#+9WEYybHeZv}*cbdmPDkPU(jb+Sl1(!A;;QmZ9oNWRty}&5QMWy9 zX_w<YIby`Y;2BC{-IfA^=3f)~-*KF*rKr=krZyJeUl;NhG@Ajb2fr2VF0H7ZuP8_; zl#_lD<2+R)LHx3c896sfpWG@kpwT@>#$6|4gx_Jt0Gfn8w&q}%lq4QU%6#jT*MRT% zrLz~C8FYKHawn-EQWN1B75O&quS+Z81(zN)G>~vN8VwC+e+y(`>HcxC{MrJ;H1Z4k zZWuv$w_F0-Ub%MVcpIc){4PGL^I7M{>;hS?;eH!;<Yf7EM>gmcOE66z3;Z1Phqo(t zVP(Hg6q#0gIKgsg7L7WE!{Y#1nI(45tx2{$34dDd#!Z0NIyrm)HOn5W#7;f4pQci# zDW!FI(g4e668kI9{2+mLwB+=#9bfqgX%!B34V-$wwSN(_cm*^{y0jQtv*4}eO^sOV z*9xoNvX)c9isB}Tgx&ZRjp3kwhTVK?r9;n<haxnrRq){mtk9A+#MWR@iL>!x>^XYT z@Q^7zp{rkIs{2mUSE^2!Gf6$6;j~&4=-0cSJJDizZp6LTe8b45;{AKM%v99}{{FfC zz709%u0mC=1KXTo(=TqmZQ;c?$M3z(!xah>aywrj40sc2y3rKFw4jCq+Y+u=CH@_V zxz|qeTwa>+<|H%8Dz5u>ZI5MmjTFwXS-Fv!TDd*`>3{krWoNVx$<133`(ftS?ZPyY z&4@ah^3^i`vL$BZa>O|Nt?ucewzsF)0zX3qmM^|waXr=T0pfIb0*$AwU=?Ipl|1Y; z*Pk6{C-p4MY;j@IJ|DW<V4g+WfmkDAI{!240rBm;^p*C?EK5<-i6<dFN`<4WIVA6x zQ_A}VBKmDESd)f<tKV+_7{`O-ZQ=Kw_N>>QHZQJcp;Z~?8(Q+Kk3^0qJ}SCk^*n4W zu9ZFwLHUx-$6xvaQ)SUQcYd6fF8&x)V`1bIuX@>{mE$b|Yd(qomn3;bPwnDUc0F=; zh*6_((%bqAYQWQ~odER?h>1mkL4kpb3s7`0m@rDKGU*oyF)$j~Ffd4fXV$?`f~rHf z<dmhsigJ=rWi_aV`WXyhB>B%Y)@5SXZvfwm10RY5X?TEo)PK_`L6qgBp=#>fO49$D zDq8Ozj0q6213tV5Qq=;fZ0$|KroY{Dz=l@lU^J)?Ko@ti20TRplXzphBi>XGx4bou zEWrkNjz0t5j!_ke{g5I#PUlEU$Km8g8TE|XK=MkU@PT4T><2OVamoK;wJ}3X0L$vX zgd7gNa359*nc)R-0!`2X@FOTB`+oETOPc=ubp5R)VQgY+5BTZZJ2<L28T@@Z{~(FZ zheu(w_rw1D2_zLx!dpDtOmwLC!DhBIo<Q>?9QwnO=<wr%&Gfr?0?EHFALMv;_+d?S zzAg%@ydS-+C)WJy(gMckj>dnulIUF3gFn;BODC2)65)HeVd%t86sL7Rv^Y+nbn+&l z6BAJY(ETvwI)Ts$aiE8rht4KD*qNyE{8{x6R|%akbTBzw;2+6<pQ&SDXNQj*or8md z6z#{?Yky9DqRtSV0CMnGmM?NZ;=ja)lj3y_HwGOxfijBU4|3qigw`1zRQjL!B8PR+ zaRn%p#eR@M4(R@Wz!rx^(f#sKB!vBtl{_H&pMv^{xCn<;&`rM&o>Echkt+W+`u^XX z_z&x%n<Jwv#rI=O_ITYt8jK&7Lbvimxh?Mpm*TNff4FbaUEWX?w*B~|ab(^T*a99t zcJ#fCD8IP<V1pf_@pm2K2=}<d0_Y2*QClSUBi8yzf&VOuJ`CJAoEUwr?!mKD=5}o2 zV^&)q)<B;SMXmbXj|caU)A+-MMW5C}&8F^$XYi3}kDOaQe6Z+qH3z$S;;<vL9ydXD zI5~P97&YCq9}$m^On$P-pTjcf#j%4IH8Sc*nG=+l4{M+gXHaFf{g{b8PUBySZmJ4r UfUyy3EX0IC28@JalTrWuAK7&_a{vGU diff --git a/server/gradle/wrapper/gradle-wrapper.properties b/server/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index a4413138c..000000000 --- a/server/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/server/gradlew b/server/gradlew deleted file mode 100755 index b740cf133..000000000 --- a/server/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/server/gradlew.bat b/server/gradlew.bat deleted file mode 100644 index 25da30dbd..000000000 --- a/server/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/server/settings.gradle b/server/settings.gradle deleted file mode 100644 index dbbee46fb..000000000 --- a/server/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'haengdong' diff --git a/server/src/main/java/server/haengdong/HaengdongApplication.java b/server/src/main/java/server/haengdong/HaengdongApplication.java deleted file mode 100644 index 31b6e46e7..000000000 --- a/server/src/main/java/server/haengdong/HaengdongApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -package server.haengdong; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class HaengdongApplication { - - public static void main(String[] args) { - SpringApplication.run(HaengdongApplication.class, args); - } - -} diff --git a/server/src/main/java/server/haengdong/application/ActionService.java b/server/src/main/java/server/haengdong/application/ActionService.java deleted file mode 100644 index bda638756..000000000 --- a/server/src/main/java/server/haengdong/application/ActionService.java +++ /dev/null @@ -1,37 +0,0 @@ -package server.haengdong.application; - -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import server.haengdong.application.response.MemberBillReportAppResponse; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.BillActionRepository; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionRepository; -import server.haengdong.domain.action.MemberBillReport; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -@RequiredArgsConstructor -@Service -public class ActionService { - - private final BillActionRepository billActionRepository; - private final MemberActionRepository memberActionRepository; - private final EventRepository eventRepository; - - public List<MemberBillReportAppResponse> getMemberBillReports(String token) { - Event event = eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); - List<BillAction> billActions = billActionRepository.findByAction_Event(event); - List<MemberAction> memberActions = memberActionRepository.findAllByEvent(event); - - MemberBillReport memberBillReport = MemberBillReport.createByActions(billActions, memberActions); - - return memberBillReport.getReports().entrySet().stream() - .map(entry -> new MemberBillReportAppResponse(entry.getKey(), entry.getValue())) - .toList(); - } -} diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java deleted file mode 100644 index 257d33a3e..000000000 --- a/server/src/main/java/server/haengdong/application/BillActionService.java +++ /dev/null @@ -1,44 +0,0 @@ -package server.haengdong.application; - -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import server.haengdong.application.request.BillActionAppRequest; -import server.haengdong.domain.action.Action; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.action.ActionRepository; -import server.haengdong.domain.action.BillActionRepository; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -@RequiredArgsConstructor -@Transactional(readOnly = true) -@Service -public class BillActionService { - - private final BillActionRepository billActionRepository; - private final ActionRepository actionRepository; - private final EventRepository eventRepository; - - @Transactional - public void saveAllBillAction(String eventToken, List<BillActionAppRequest> requests) { - Event event = eventRepository.findByToken(eventToken) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); - Action action = createStartAction(event); - - for (BillActionAppRequest request : requests) { - BillAction billAction = request.toBillAction(action); - billActionRepository.save(billAction); - action = action.next(); - } - } - - private Action createStartAction(Event event) { - return actionRepository.findLastByEvent(event) - .map(Action::next) - .orElse(Action.createFirst(event)); - } -} diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java deleted file mode 100644 index 9ad502606..000000000 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ /dev/null @@ -1,91 +0,0 @@ -package server.haengdong.application; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import server.haengdong.application.request.EventAppRequest; -import server.haengdong.application.response.ActionAppResponse; -import server.haengdong.application.response.EventAppResponse; -import server.haengdong.application.response.EventDetailAppResponse; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.BillActionRepository; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionRepository; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.domain.event.EventTokenProvider; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -@RequiredArgsConstructor -@Transactional(readOnly = true) -@Service -public class EventService { - - private final EventRepository eventRepository; - private final EventTokenProvider eventTokenProvider; - private final BillActionRepository billActionRepository; - private final MemberActionRepository memberActionRepository; - - @Transactional - public EventAppResponse saveEvent(EventAppRequest request) { - String token = eventTokenProvider.createToken(); - Event event = request.toEvent(token); - eventRepository.save(event); - - return EventAppResponse.of(event); - } - - public EventDetailAppResponse findEvent(String token) { - Event event = eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); - - return EventDetailAppResponse.of(event); - } - - public List<ActionAppResponse> findActions(String token) { - Event event = eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); - - List<BillAction> billActions = billActionRepository.findByAction_Event(event).stream() - .sorted(Comparator.comparing(BillAction::getSequence)).toList(); - List<MemberAction> memberActions = memberActionRepository.findAllByEvent(event).stream() - .sorted(Comparator.comparing(MemberAction::getSequence)).toList(); - - return getActionAppResponses(billActions, memberActions); - } - - private List<ActionAppResponse> getActionAppResponses( - List<BillAction> billActions, - List<MemberAction> memberActions - ) { - int billActionIndex = 0; - int memberActionIndex = 0; - List<ActionAppResponse> actionAppResponses = new ArrayList<>(); - - while (billActionIndex < billActions.size() && memberActionIndex < memberActions.size()) { - BillAction billAction = billActions.get(billActionIndex); - MemberAction memberAction = memberActions.get(memberActionIndex); - if (billAction.getSequence() < memberAction.getSequence()) { - actionAppResponses.add(ActionAppResponse.of(billAction)); - billActionIndex++; - } else { - actionAppResponses.add(ActionAppResponse.of(memberAction)); - memberActionIndex++; - } - } - while (billActionIndex < billActions.size()) { - BillAction billAction = billActions.get(billActionIndex++); - actionAppResponses.add(ActionAppResponse.of(billAction)); - } - while (memberActionIndex < memberActions.size()) { - MemberAction memberAction = memberActions.get(memberActionIndex++); - actionAppResponses.add(ActionAppResponse.of(memberAction)); - } - - return actionAppResponses; - } -} diff --git a/server/src/main/java/server/haengdong/application/MemberActionFactory.java b/server/src/main/java/server/haengdong/application/MemberActionFactory.java deleted file mode 100644 index cbe34f0ef..000000000 --- a/server/src/main/java/server/haengdong/application/MemberActionFactory.java +++ /dev/null @@ -1,82 +0,0 @@ -package server.haengdong.application; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; -import server.haengdong.application.request.MemberActionSaveAppRequest; -import server.haengdong.application.request.MemberActionsSaveAppRequest; -import server.haengdong.domain.action.Action; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionStatus; -import server.haengdong.domain.action.MemberGroupIdProvider; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -@RequiredArgsConstructor -@Component -public class MemberActionFactory { - - private final MemberGroupIdProvider memberGroupIdProvider; - - public List<MemberAction> createMemberActions( - MemberActionsSaveAppRequest request, - List<MemberAction> memberActions, - Action action - ) { - validateMemberNames(request); - validateActions(request, memberActions); - - Long memberGroupId = memberGroupIdProvider.createGroupId(); - List<MemberAction> createdMemberActions = new ArrayList<>(); - List<MemberActionSaveAppRequest> actions = request.actions(); - for (MemberActionSaveAppRequest appRequest : actions) { - MemberAction memberAction = appRequest.toMemberAction(action, memberGroupId); - createdMemberActions.add(memberAction); - action = action.next(); - } - - return createdMemberActions; - } - - private void validateMemberNames(MemberActionsSaveAppRequest request) { - List<String> memberNames = request.actions().stream() - .map(MemberActionSaveAppRequest::name) - .toList(); - - long uniqueCount = memberNames.stream().distinct().count(); - if (uniqueCount != memberNames.size()) { - throw new HaengdongException(HaengdongErrorCode.DUPLICATED_MEMBER_ACTION); - } - } - - private void validateActions(MemberActionsSaveAppRequest request, List<MemberAction> memberActions) { - List<MemberAction> reverseSortedMemberActions = memberActions.stream() - .sorted(Comparator.comparing(MemberAction::getSequence).reversed()) - .toList(); - - for (MemberActionSaveAppRequest action : request.actions()) { - validateAction(action, reverseSortedMemberActions); - } - } - - private void validateAction(MemberActionSaveAppRequest request, List<MemberAction> memberActions) { - MemberActionStatus memberActionStatus = MemberActionStatus.of(request.status()); - if (isInvalidStatus(memberActions, request.name(), memberActionStatus)) { - throw new HaengdongException(HaengdongErrorCode.INVALID_MEMBER_ACTION); - } - } - - private boolean isInvalidStatus( - List<MemberAction> memberActions, - String memberName, - MemberActionStatus memberActionStatus - ) { - return memberActions.stream() - .filter(action -> action.isSameName(memberName)) - .findFirst() - .map(action -> action.isSameStatus(memberActionStatus)) - .orElse(MemberActionStatus.IN != memberActionStatus); - } -} diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java deleted file mode 100644 index 5094bf2c0..000000000 --- a/server/src/main/java/server/haengdong/application/MemberActionService.java +++ /dev/null @@ -1,60 +0,0 @@ -package server.haengdong.application; - -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import server.haengdong.application.request.MemberActionsSaveAppRequest; -import server.haengdong.application.response.CurrentMemberAppResponse; -import server.haengdong.domain.action.Action; -import server.haengdong.domain.action.ActionRepository; -import server.haengdong.domain.action.CurrentMembers; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionRepository; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -@RequiredArgsConstructor -@Transactional(readOnly = true) -@Service -public class MemberActionService { - - private final MemberActionFactory memberActionFactory; - private final MemberActionRepository memberActionRepository; - private final EventRepository eventRepository; - private final ActionRepository actionRepository; - - @Transactional - public void saveMemberAction(String token, MemberActionsSaveAppRequest request) { - Event event = findEvent(token); - - List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event); - Action action = createStartAction(event); - List<MemberAction> memberActions = memberActionFactory.createMemberActions(request, findMemberActions, action); - memberActionRepository.saveAll(memberActions); - } - - private Action createStartAction(Event event) { - return actionRepository.findLastByEvent(event) - .map(Action::next) - .orElse(Action.createFirst(event)); - } - - public List<CurrentMemberAppResponse> getCurrentMembers(String token) { - Event event = findEvent(token); - List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event); - CurrentMembers currentMembers = CurrentMembers.of(findMemberActions); - - return currentMembers.getMembers() - .stream() - .map(CurrentMemberAppResponse::new) - .toList(); - } - - private Event findEvent(String token) { - return eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); - } -} diff --git a/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java deleted file mode 100644 index acd0149f9..000000000 --- a/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java +++ /dev/null @@ -1,14 +0,0 @@ -package server.haengdong.application.request; - -import server.haengdong.domain.action.Action; -import server.haengdong.domain.action.BillAction; - -public record BillActionAppRequest( - String title, - Long price -) { - - public BillAction toBillAction(Action action) { - return new BillAction(action, title, price); - } -} diff --git a/server/src/main/java/server/haengdong/application/request/EventAppRequest.java b/server/src/main/java/server/haengdong/application/request/EventAppRequest.java deleted file mode 100644 index 1eea6adf4..000000000 --- a/server/src/main/java/server/haengdong/application/request/EventAppRequest.java +++ /dev/null @@ -1,10 +0,0 @@ -package server.haengdong.application.request; - -import server.haengdong.domain.event.Event; - -public record EventAppRequest(String name) { - - public Event toEvent(String token) { - return new Event(name, token); - } -} diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java deleted file mode 100644 index f7f8d8fc2..000000000 --- a/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java +++ /dev/null @@ -1,12 +0,0 @@ -package server.haengdong.application.request; - -import server.haengdong.domain.action.Action; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionStatus; - -public record MemberActionSaveAppRequest(String name, String status) { - - public MemberAction toMemberAction(Action action, Long memberGroupId) { - return new MemberAction(action, name, MemberActionStatus.of(status), memberGroupId); - } -} diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java deleted file mode 100644 index 650b908df..000000000 --- a/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java +++ /dev/null @@ -1,6 +0,0 @@ -package server.haengdong.application.request; - -import java.util.List; - -public record MemberActionsSaveAppRequest(List<MemberActionSaveAppRequest> actions) { -} diff --git a/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java b/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java deleted file mode 100644 index a1abcc35b..000000000 --- a/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java +++ /dev/null @@ -1,54 +0,0 @@ -package server.haengdong.application.response; - -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionStatus; - -public record ActionAppResponse( - Long actionId, - String name, - Long price, - Long sequence, - ActionType actionType -) { - - public static ActionAppResponse of(BillAction billAction) { - return new ActionAppResponse( - billAction.getAction().getId(), - billAction.getTitle(), - billAction.getPrice(), - billAction.getSequence(), - ActionType.BILL - ); - } - - public static ActionAppResponse of(MemberAction memberAction) { - MemberActionStatus status = memberAction.getStatus(); - - return new ActionAppResponse( - memberAction.getAction().getId(), - memberAction.getMemberName(), - null, - memberAction.getSequence(), - ActionType.of(status) - ); - } - - public String actionTypeName() { - return actionType.name(); - } - - public enum ActionType { - BILL, - IN, - OUT, - ; - - private static ActionType of(MemberActionStatus memberActionStatus) { - if (MemberActionStatus.IN == memberActionStatus) { - return IN; - } - return OUT; - } - } -} diff --git a/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java b/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java deleted file mode 100644 index 6c682d3e9..000000000 --- a/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package server.haengdong.application.response; - -import server.haengdong.domain.action.MemberAction; - -public record CurrentMemberAppResponse(String name) { - - public static CurrentMemberAppResponse of(MemberAction memberAction) { - return new CurrentMemberAppResponse(memberAction.getMemberName()); - } -} diff --git a/server/src/main/java/server/haengdong/application/response/EventAppResponse.java b/server/src/main/java/server/haengdong/application/response/EventAppResponse.java deleted file mode 100644 index f331d0011..000000000 --- a/server/src/main/java/server/haengdong/application/response/EventAppResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package server.haengdong.application.response; - -import server.haengdong.domain.event.Event; - -public record EventAppResponse(String token) { - - public static EventAppResponse of(Event event) { - return new EventAppResponse(event.getToken()); - } -} diff --git a/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java b/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java deleted file mode 100644 index 6e38826d4..000000000 --- a/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package server.haengdong.application.response; - -import server.haengdong.domain.event.Event; - -public record EventDetailAppResponse(String eventName) { - - public static EventDetailAppResponse of(Event event) { - return new EventDetailAppResponse(event.getName()); - } -} diff --git a/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java b/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java deleted file mode 100644 index 21b6cef56..000000000 --- a/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java +++ /dev/null @@ -1,4 +0,0 @@ -package server.haengdong.application.response; - -public record MemberBillReportAppResponse(String name, Long price) { -} diff --git a/server/src/main/java/server/haengdong/config/WebConfig.java b/server/src/main/java/server/haengdong/config/WebConfig.java deleted file mode 100644 index 129d8b790..000000000 --- a/server/src/main/java/server/haengdong/config/WebConfig.java +++ /dev/null @@ -1,27 +0,0 @@ -package server.haengdong.config; - -import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.CorsRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -@RequiredArgsConstructor -@Configuration -public class WebConfig implements WebMvcConfigurer { - - @Value("${cors.max-age}") - private Long maxAge; - - @Value("${cors.allowed-origins}") - private String[] allowedOrigins; - - @Override - public void addCorsMappings(CorsRegistry registry) { - registry.addMapping("/**") - .allowedOrigins(allowedOrigins) - .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS") - .allowedHeaders("*") - .maxAge(maxAge); - } -} diff --git a/server/src/main/java/server/haengdong/domain/action/Action.java b/server/src/main/java/server/haengdong/domain/action/Action.java deleted file mode 100644 index 11f91fc38..000000000 --- a/server/src/main/java/server/haengdong/domain/action/Action.java +++ /dev/null @@ -1,42 +0,0 @@ -package server.haengdong.domain.action; - -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.ManyToOne; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import server.haengdong.domain.event.Event; - -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@Entity -public class Action { - - private static final long FIRST_SEQUENCE = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @ManyToOne(fetch = FetchType.LAZY) - private Event event; - - private Long sequence; - - public Action(Event event, Long sequence) { - this.event = event; - this.sequence = sequence; - } - - public static Action createFirst(Event event) { - return new Action(event, FIRST_SEQUENCE); - } - - public Action next() { - return new Action(event, sequence + 1); - } -} diff --git a/server/src/main/java/server/haengdong/domain/action/ActionRepository.java b/server/src/main/java/server/haengdong/domain/action/ActionRepository.java deleted file mode 100644 index c2138e42f..000000000 --- a/server/src/main/java/server/haengdong/domain/action/ActionRepository.java +++ /dev/null @@ -1,21 +0,0 @@ -package server.haengdong.domain.action; - -import java.util.Optional; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; -import server.haengdong.domain.event.Event; - -@Repository -public interface ActionRepository extends JpaRepository<Action, Long> { - - @Query(""" - SELECT a - FROM Action a - WHERE a.event = :event - ORDER BY a.sequence DESC - LIMIT 1 - """) - Optional<Action> findLastByEvent(@Param("event") Event event); -} diff --git a/server/src/main/java/server/haengdong/domain/action/BillAction.java b/server/src/main/java/server/haengdong/domain/action/BillAction.java deleted file mode 100644 index 1027206f5..000000000 --- a/server/src/main/java/server/haengdong/domain/action/BillAction.java +++ /dev/null @@ -1,70 +0,0 @@ -package server.haengdong.domain.action; - -import jakarta.persistence.CascadeType; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.OneToOne; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@Entity -public class BillAction implements Comparable<BillAction> { - - private static final int MIN_TITLE_LENGTH = 2; - private static final int MAX_TITLE_LENGTH = 30; - private static final long MIN_PRICE = 1L; - private static final long MAX_PRICE = 10_000_000L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) - private Action action; - - @Column(length = MAX_TITLE_LENGTH) - private String title; - - private Long price; - - public BillAction(Action action, String title, Long price) { - validateTitle(title); - validatePrice(price); - this.action = action; - this.title = title.trim(); - this.price = price; - } - - private void validateTitle(String title) { - int titleLength = title.trim().length(); - if (titleLength < MIN_TITLE_LENGTH || titleLength > MAX_TITLE_LENGTH) { - throw new HaengdongException(HaengdongErrorCode.BAD_REQUEST, - String.format("앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다.", MIN_TITLE_LENGTH, MAX_TITLE_LENGTH)); - } - } - - private void validatePrice(Long price) { - if (price < MIN_PRICE || price > MAX_PRICE) { - throw new HaengdongException(HaengdongErrorCode.BAD_REQUEST, - String.format("지출 금액은 %,d 이하의 자연수여야 합니다.", MAX_PRICE)); - } - } - - public Long getSequence() { - return action.getSequence(); - } - - @Override - public int compareTo(BillAction o) { - return Long.compare(this.getSequence(), o.getSequence()); - } -} diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java deleted file mode 100644 index 1ad7416aa..000000000 --- a/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java +++ /dev/null @@ -1,14 +0,0 @@ -package server.haengdong.domain.action; - -import java.util.List; -import org.springframework.data.jpa.repository.EntityGraph; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; -import server.haengdong.domain.event.Event; - -@Repository -public interface BillActionRepository extends JpaRepository<BillAction, Long> { - - @EntityGraph(attributePaths = {"action"}) - List<BillAction> findByAction_Event(Event event); -} diff --git a/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java b/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java deleted file mode 100644 index 298a8a965..000000000 --- a/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java +++ /dev/null @@ -1,66 +0,0 @@ -package server.haengdong.domain.action; - -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -public class CurrentMembers { - - private final Set<String> members; - - public CurrentMembers() { - this(new HashSet<>()); - } - - private CurrentMembers(Set<String> members) { - this.members = members; - } - - public static CurrentMembers of(List<MemberAction> memberActions) { - List<MemberAction> sortedMemberActions = getSortedMemberActions(memberActions); - Set<String> members = new HashSet<>(); - for (MemberAction memberAction : sortedMemberActions) { - String member = memberAction.getMemberName(); - if (memberAction.isSameStatus(MemberActionStatus.IN)) { - members.add(member); - continue; - } - members.remove(member); - } - - return new CurrentMembers(members); - } - - private static List<MemberAction> getSortedMemberActions(List<MemberAction> memberActions) { - return memberActions.stream() - .sorted(Comparator.comparing(MemberAction::getSequence)) - .toList(); - } - - public CurrentMembers addMemberAction(MemberAction memberAction) { - String memberName = memberAction.getMemberName(); - - Set<String> currentMembers = new HashSet<>(members); - - if (memberAction.isIn()) { - currentMembers.add(memberName); - } else { - currentMembers.remove(memberName); - } - return new CurrentMembers(currentMembers); - } - - public boolean isEmpty() { - return members.isEmpty(); - } - - public int size() { - return members.size(); - } - - public Set<String> getMembers() { - return Collections.unmodifiableSet(members); - } -} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberAction.java b/server/src/main/java/server/haengdong/domain/action/MemberAction.java deleted file mode 100644 index 67387cbde..000000000 --- a/server/src/main/java/server/haengdong/domain/action/MemberAction.java +++ /dev/null @@ -1,62 +0,0 @@ -package server.haengdong.domain.action; - -import jakarta.persistence.CascadeType; -import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.OneToOne; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@Entity -public class MemberAction implements Comparable<MemberAction> { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) - private Action action; - - private String memberName; - - @Enumerated(EnumType.STRING) - private MemberActionStatus status; - - private Long memberGroupId; - - public MemberAction(Action action, String memberName, MemberActionStatus status, Long memberGroupId) { - this.action = action; - this.memberName = memberName; - this.status = status; - this.memberGroupId = memberGroupId; - } - - public boolean isSameName(String name) { - return memberName.equals(name); - } - - public boolean isIn() { - return status == MemberActionStatus.IN; - } - - public boolean isSameStatus(MemberActionStatus memberActionStatus) { - return status == memberActionStatus; - } - - public Long getSequence() { - return action.getSequence(); - } - - @Override - public int compareTo(MemberAction o) { - return Long.compare(this.getSequence(), o.getSequence()); - } -} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java deleted file mode 100644 index 6c4769e61..000000000 --- a/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java +++ /dev/null @@ -1,15 +0,0 @@ -package server.haengdong.domain.action; - -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; -import server.haengdong.domain.event.Event; - -@Repository -public interface MemberActionRepository extends JpaRepository<MemberAction, Long> { - - @Query("select m from MemberAction m join fetch m.action where m.action.event = :event") - List<MemberAction> findAllByEvent(@Param("event") Event event); -} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java b/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java deleted file mode 100644 index 0a20817fd..000000000 --- a/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java +++ /dev/null @@ -1,19 +0,0 @@ -package server.haengdong.domain.action; - -import java.util.Arrays; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -public enum MemberActionStatus { - IN, - OUT, - ; - - public static MemberActionStatus of(String status) { - return Arrays.stream(MemberActionStatus.values()) - .filter(s -> s.name().equals(status)) - .findFirst() - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BAD_REQUEST, - "존재하지 않는 인원 변동 액션입니다.")); - } -} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java b/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java deleted file mode 100644 index dbf2b49ac..000000000 --- a/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java +++ /dev/null @@ -1,75 +0,0 @@ -package server.haengdong.domain.action; - -import static java.util.stream.Collectors.toMap; - -import java.util.List; -import java.util.Map; -import java.util.PriorityQueue; -import java.util.function.Function; -import lombok.Getter; - -@Getter -public class MemberBillReport { - - private final Map<String, Long> reports; - - private MemberBillReport(Map<String, Long> reports) { - this.reports = reports; - } - - public static MemberBillReport createByActions(List<BillAction> billActions, List<MemberAction> memberActions) { - PriorityQueue<BillAction> sortedBillActions = new PriorityQueue<>(billActions); - PriorityQueue<MemberAction> sortedMemberActions = new PriorityQueue<>(memberActions); - - Map<String, Long> memberBillReports = initReports(memberActions); - CurrentMembers currentMembers = new CurrentMembers(); - while (!sortedBillActions.isEmpty() && !sortedMemberActions.isEmpty()) { - if (isMemberActionTurn(sortedMemberActions, sortedBillActions)) { - MemberAction memberAction = sortedMemberActions.poll(); - currentMembers = currentMembers.addMemberAction(memberAction); - continue; - } - addBillAction(sortedBillActions, currentMembers, memberBillReports); - } - - while (!sortedBillActions.isEmpty()) { - addBillAction(sortedBillActions, currentMembers, memberBillReports); - } - - return new MemberBillReport(memberBillReports); - } - - private static Map<String, Long> initReports(List<MemberAction> memberActions) { - return memberActions.stream() - .map(MemberAction::getMemberName) - .distinct() - .collect(toMap(Function.identity(), i -> 0L)); - } - - private static boolean isMemberActionTurn( - PriorityQueue<MemberAction> memberActions, - PriorityQueue<BillAction> billActions - ) { - MemberAction memberAction = memberActions.peek(); - BillAction billAction = billActions.peek(); - - return memberAction.getSequence() < billAction.getSequence(); - } - - private static void addBillAction( - PriorityQueue<BillAction> sortedBillActions, - CurrentMembers currentMembers, - Map<String, Long> memberBillReports - ) { - BillAction billAction = sortedBillActions.poll(); - if (currentMembers.isEmpty()) { - return; - } - - Long pricePerMember = billAction.getPrice() / currentMembers.size(); - for (String currentMember : currentMembers.getMembers()) { - Long price = memberBillReports.get(currentMember) + pricePerMember; - memberBillReports.put(currentMember, price); - } - } -} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java b/server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java deleted file mode 100644 index 9e32bd733..000000000 --- a/server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java +++ /dev/null @@ -1,11 +0,0 @@ -package server.haengdong.domain.action; - -import org.springframework.stereotype.Component; - -@Component -public class MemberGroupIdProvider { - - public Long createGroupId() { - return System.currentTimeMillis(); - } -} diff --git a/server/src/main/java/server/haengdong/domain/event/Event.java b/server/src/main/java/server/haengdong/domain/event/Event.java deleted file mode 100644 index 24369a184..000000000 --- a/server/src/main/java/server/haengdong/domain/event/Event.java +++ /dev/null @@ -1,54 +0,0 @@ -package server.haengdong.domain.event; - -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@Entity -public class Event { - - private static final int MIN_NAME_LENGTH = 2; - private static final int MAX_NAME_LENGTH = 20; - private static final String SPACES = " "; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - private String name; - - private String token; - - public Event(String name, String token) { - validateName(name); - this.name = name; - this.token = token; - } - - private void validateName(String name) { - int nameLength = name.length(); - if (nameLength < MIN_NAME_LENGTH || MAX_NAME_LENGTH < nameLength) { - throw new HaengdongException(HaengdongErrorCode.BAD_REQUEST, - String.format("행사 이름은 %d자 이상 %d자 이하만 입력 가능합니다. 입력한 이름 길이 : %d", - MIN_NAME_LENGTH, - MAX_NAME_LENGTH, - name.length())); - } - if (isBlankContinuous(name)) { - throw new HaengdongException(HaengdongErrorCode.BAD_REQUEST, - String.format("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s", name)); - } - } - - private boolean isBlankContinuous(String name) { - return name.contains(SPACES); - } -} diff --git a/server/src/main/java/server/haengdong/domain/event/EventRepository.java b/server/src/main/java/server/haengdong/domain/event/EventRepository.java deleted file mode 100644 index 6038c368b..000000000 --- a/server/src/main/java/server/haengdong/domain/event/EventRepository.java +++ /dev/null @@ -1,11 +0,0 @@ -package server.haengdong.domain.event; - -import java.util.Optional; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface EventRepository extends JpaRepository<Event, Long> { - - Optional<Event> findByToken(String token); -} diff --git a/server/src/main/java/server/haengdong/domain/event/EventStep.java b/server/src/main/java/server/haengdong/domain/event/EventStep.java deleted file mode 100644 index 297abdb66..000000000 --- a/server/src/main/java/server/haengdong/domain/event/EventStep.java +++ /dev/null @@ -1,28 +0,0 @@ -package server.haengdong.domain.event; - -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.ManyToOne; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@Entity -public class EventStep { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @ManyToOne(fetch = FetchType.LAZY) - private Event event; - - private String name; - - private Long sequence; -} diff --git a/server/src/main/java/server/haengdong/domain/event/EventTokenProvider.java b/server/src/main/java/server/haengdong/domain/event/EventTokenProvider.java deleted file mode 100644 index 6450f0dcf..000000000 --- a/server/src/main/java/server/haengdong/domain/event/EventTokenProvider.java +++ /dev/null @@ -1,12 +0,0 @@ -package server.haengdong.domain.event; - -import java.util.UUID; -import org.springframework.stereotype.Component; - -@Component -public class EventTokenProvider { - - public String createToken() { - return UUID.randomUUID().toString(); - } -} diff --git a/server/src/main/java/server/haengdong/exception/ErrorResponse.java b/server/src/main/java/server/haengdong/exception/ErrorResponse.java deleted file mode 100644 index c797b811a..000000000 --- a/server/src/main/java/server/haengdong/exception/ErrorResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package server.haengdong.exception; - -public record ErrorResponse( - String message -) { - - public static ErrorResponse of(String message) { - return new ErrorResponse(message); - } -} diff --git a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java deleted file mode 100644 index bb3138cc7..000000000 --- a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java +++ /dev/null @@ -1,43 +0,0 @@ -package server.haengdong.exception; - -import java.util.stream.Collectors; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; -import org.springframework.web.HttpRequestMethodNotSupportedException; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.RestControllerAdvice; - -@Slf4j -@RestControllerAdvice -public class GlobalExceptionHandler { - - @ExceptionHandler(HttpRequestMethodNotSupportedException.class) - public ResponseEntity<ErrorResponse> haengdongException() { - return ResponseEntity.badRequest() - .body(ErrorResponse.of(HaengdongErrorCode.BAD_REQUEST.getMessage())); - } - - @ExceptionHandler(MethodArgumentNotValidException.class) - public ResponseEntity<ErrorResponse> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { - String errorMessage = e.getFieldErrors().stream() - .map(error -> error.getField() + " " + error.getDefaultMessage()) - .collect(Collectors.joining(", ")); - - return ResponseEntity.badRequest() - .body(ErrorResponse.of(errorMessage)); - } - - @ExceptionHandler(HaengdongException.class) - public ResponseEntity<ErrorResponse> haengdongException(HaengdongException e) { - return ResponseEntity.status(e.getStatusCode()) - .body(ErrorResponse.of(e.getMessage())); - } - - @ExceptionHandler(Exception.class) - public ResponseEntity<ErrorResponse> handleException(Exception e) { - log.error(e.getMessage(), e); - return ResponseEntity.internalServerError() - .body(ErrorResponse.of(HaengdongErrorCode.INTERNAL_SERVER_ERROR.getMessage())); - } -} diff --git a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java deleted file mode 100644 index 792baa838..000000000 --- a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java +++ /dev/null @@ -1,24 +0,0 @@ -package server.haengdong.exception; - -import lombok.Getter; -import org.springframework.http.HttpStatus; - -@Getter -public enum HaengdongErrorCode { - BAD_REQUEST(HttpStatus.BAD_REQUEST, "잘못된 요청입니다."), - DUPLICATED_MEMBER_ACTION(HttpStatus.BAD_REQUEST, "올바르지 않은 인원 요청입니다."), - INVALID_MEMBER_ACTION(HttpStatus.BAD_REQUEST, "잘못된 맴버 액션입니다."), - - NOT_FOUND_EVENT(HttpStatus.NOT_FOUND, "존재하지 않는 행사입니다."), - - INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버 내부에서 에러가 발생했습니다."), - ; - - private final HttpStatus httpStatus; - private final String message; - - HaengdongErrorCode(HttpStatus httpStatus, String message) { - this.httpStatus = httpStatus; - this.message = message; - } -} diff --git a/server/src/main/java/server/haengdong/exception/HaengdongException.java b/server/src/main/java/server/haengdong/exception/HaengdongException.java deleted file mode 100644 index 812df50f8..000000000 --- a/server/src/main/java/server/haengdong/exception/HaengdongException.java +++ /dev/null @@ -1,32 +0,0 @@ -package server.haengdong.exception; - -import lombok.Getter; -import org.springframework.http.HttpStatusCode; - -@Getter -public class HaengdongException extends RuntimeException { - - private final HaengdongErrorCode errorCode; - private final String message; - - public HaengdongException(HaengdongErrorCode errorCode) { - this(errorCode, null); - } - - public HaengdongException(HaengdongErrorCode errorCode, String message) { - this.errorCode = errorCode; - this.message = message; - } - - public HttpStatusCode getStatusCode() { - return errorCode.getHttpStatus(); - } - - @Override - public String getMessage() { - if (message == null) { - return errorCode.getMessage(); - } - return message; - } -} diff --git a/server/src/main/java/server/haengdong/presentation/ActionController.java b/server/src/main/java/server/haengdong/presentation/ActionController.java deleted file mode 100644 index 657cb567e..000000000 --- a/server/src/main/java/server/haengdong/presentation/ActionController.java +++ /dev/null @@ -1,26 +0,0 @@ -package server.haengdong.presentation; - -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RestController; -import server.haengdong.application.ActionService; -import server.haengdong.application.response.MemberBillReportAppResponse; -import server.haengdong.presentation.response.MemberBillReportsResponse; - -@RequiredArgsConstructor -@RestController -public class ActionController { - - private final ActionService actionService; - - @GetMapping("/api/events/{eventId}/actions/reports") - public ResponseEntity<MemberBillReportsResponse> getMemberBillReports(@PathVariable("eventId") String token) { - List<MemberBillReportAppResponse> memberBillReports = actionService.getMemberBillReports(token); - - return ResponseEntity.ok() - .body(MemberBillReportsResponse.of(memberBillReports)); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/BillActionController.java b/server/src/main/java/server/haengdong/presentation/BillActionController.java deleted file mode 100644 index fcdacb270..000000000 --- a/server/src/main/java/server/haengdong/presentation/BillActionController.java +++ /dev/null @@ -1,29 +0,0 @@ -package server.haengdong.presentation; - -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; -import server.haengdong.application.BillActionService; -import server.haengdong.presentation.request.BillActionsSaveRequest; - -@RequiredArgsConstructor -@RestController -public class BillActionController { - - private final BillActionService billActionService; - - @PostMapping("/api/events/{eventId}/actions/bills") - public ResponseEntity<Void> saveAllBillAction( - @PathVariable("eventId") String token, - @RequestBody @Valid BillActionsSaveRequest request - ) { - billActionService.saveAllBillAction(token, request.toAppRequests()); - - return ResponseEntity.ok() - .build(); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java deleted file mode 100644 index 9fbe098ce..000000000 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ /dev/null @@ -1,43 +0,0 @@ -package server.haengdong.presentation; - -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; -import server.haengdong.application.EventService; -import server.haengdong.presentation.request.EventSaveRequest; -import server.haengdong.presentation.response.EventDetailResponse; -import server.haengdong.presentation.response.EventResponse; -import server.haengdong.presentation.response.StepResponse; - -@RequiredArgsConstructor -@RestController -public class EventController { - - private final EventService eventService; - - @PostMapping("/api/events") - public ResponseEntity<EventResponse> saveEvent(@Valid @RequestBody EventSaveRequest request) { - EventResponse eventResponse = EventResponse.of(eventService.saveEvent(request.toAppRequest())); - - return ResponseEntity.ok(eventResponse); - } - - @GetMapping("/api/events/{eventId}") - public ResponseEntity<EventDetailResponse> findEvent(@PathVariable("eventId") String token) { - EventDetailResponse eventDetailResponse = EventDetailResponse.of(eventService.findEvent(token)); - - return ResponseEntity.ok(eventDetailResponse); - } - - @GetMapping("/api/events/{eventId}/actions") - public ResponseEntity<StepResponse> findActions(@PathVariable("eventId") String token) { - StepResponse stepResponse = StepResponse.of(eventService.findActions(token)); - - return ResponseEntity.ok(stepResponse); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/MemberActionController.java b/server/src/main/java/server/haengdong/presentation/MemberActionController.java deleted file mode 100644 index c12370d86..000000000 --- a/server/src/main/java/server/haengdong/presentation/MemberActionController.java +++ /dev/null @@ -1,39 +0,0 @@ -package server.haengdong.presentation; - -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; -import server.haengdong.application.MemberActionService; -import server.haengdong.application.response.CurrentMemberAppResponse; -import server.haengdong.presentation.request.MemberActionsSaveRequest; -import server.haengdong.presentation.response.CurrentMembersResponse; - -@RequiredArgsConstructor -@RestController -public class MemberActionController { - - private final MemberActionService memberActionService; - - @PostMapping("/api/events/{eventId}/actions/members") - public ResponseEntity<Void> saveMemberAction( - @PathVariable("eventId") String token, - @RequestBody MemberActionsSaveRequest request - ) { - memberActionService.saveMemberAction(token, request.toAppRequest()); - - return ResponseEntity.ok().build(); - } - - @GetMapping("/api/events/{eventId}/members/current") - public ResponseEntity<CurrentMembersResponse> getCurrentMembers(@PathVariable("eventId") String token) { - List<CurrentMemberAppResponse> currentMembers = memberActionService.getCurrentMembers(token); - - return ResponseEntity.ok() - .body(CurrentMembersResponse.of(currentMembers)); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java deleted file mode 100644 index a0d878f7f..000000000 --- a/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java +++ /dev/null @@ -1,19 +0,0 @@ -package server.haengdong.presentation.request; - -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import server.haengdong.application.request.BillActionAppRequest; - -public record BillActionSaveRequest( - - @NotBlank - String title, - - @NotNull - Long price -) { - - public BillActionAppRequest toAppRequest() { - return new BillActionAppRequest(title, price); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java deleted file mode 100644 index 68784039b..000000000 --- a/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java +++ /dev/null @@ -1,14 +0,0 @@ -package server.haengdong.presentation.request; - -import jakarta.validation.Valid; -import java.util.List; -import server.haengdong.application.request.BillActionAppRequest; - -public record BillActionsSaveRequest(@Valid List<BillActionSaveRequest> actions) { - - public List<BillActionAppRequest> toAppRequests() { - return actions.stream() - .map(BillActionSaveRequest::toAppRequest) - .toList(); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java deleted file mode 100644 index b28572332..000000000 --- a/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java +++ /dev/null @@ -1,15 +0,0 @@ -package server.haengdong.presentation.request; - -import jakarta.validation.constraints.NotBlank; -import server.haengdong.application.request.EventAppRequest; - -public record EventSaveRequest( - - @NotBlank - String eventName -) { - - public EventAppRequest toAppRequest() { - return new EventAppRequest(eventName); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java deleted file mode 100644 index 0b3fcebae..000000000 --- a/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java +++ /dev/null @@ -1,22 +0,0 @@ -package server.haengdong.presentation.request; - -import jakarta.validation.constraints.NotBlank; -import java.util.List; -import server.haengdong.application.request.MemberActionSaveAppRequest; -import server.haengdong.application.request.MemberActionsSaveAppRequest; - -public record MemberActionsSaveRequest( - List<String> members, - - @NotBlank - String status -) { - - public MemberActionsSaveAppRequest toAppRequest() { - List<MemberActionSaveAppRequest> appRequests = members.stream() - .map(name -> new MemberActionSaveAppRequest(name, status)) - .toList(); - - return new MemberActionsSaveAppRequest(appRequests); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java b/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java deleted file mode 100644 index a58e60186..000000000 --- a/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java +++ /dev/null @@ -1,20 +0,0 @@ -package server.haengdong.presentation.response; - -import server.haengdong.application.response.ActionAppResponse; - -public record ActionResponse( - Long actionId, - String name, - Long price, - Long sequence -) { - - public static ActionResponse of(ActionAppResponse actionAppResponse) { - return new ActionResponse( - actionAppResponse.actionId(), - actionAppResponse.name(), - actionAppResponse.price(), - actionAppResponse.sequence() - ); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java b/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java deleted file mode 100644 index 188c48dc9..000000000 --- a/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java +++ /dev/null @@ -1,28 +0,0 @@ -package server.haengdong.presentation.response; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import server.haengdong.application.response.ActionAppResponse; - -public record ActionsResponse( - String type, - String stepName, - Set<String> members, - List<ActionResponse> actions -) { - - public static ActionsResponse of(List<ActionAppResponse> actions, Set<String> members) { - List<ActionResponse> actionResponses = actions.stream() - .map(ActionResponse::of) - .toList(); - - String actionType = actions.get(0).actionTypeName(); - return new ActionsResponse( - actionType, - null, - new HashSet<>(members), - actionResponses - ); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/response/CurrentMemberResponse.java b/server/src/main/java/server/haengdong/presentation/response/CurrentMemberResponse.java deleted file mode 100644 index 4308c7d17..000000000 --- a/server/src/main/java/server/haengdong/presentation/response/CurrentMemberResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package server.haengdong.presentation.response; - -import server.haengdong.application.response.CurrentMemberAppResponse; - -public record CurrentMemberResponse(String name) { - - public static CurrentMemberResponse of(CurrentMemberAppResponse response) { - return new CurrentMemberResponse(response.name()); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java b/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java deleted file mode 100644 index 4eb915dd4..000000000 --- a/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java +++ /dev/null @@ -1,15 +0,0 @@ -package server.haengdong.presentation.response; - -import java.util.List; -import server.haengdong.application.response.CurrentMemberAppResponse; - -public record CurrentMembersResponse(List<CurrentMemberResponse> members) { - - public static CurrentMembersResponse of(List<CurrentMemberAppResponse> currentMembers) { - List<CurrentMemberResponse> responses = currentMembers.stream() - .map(CurrentMemberResponse::of) - .toList(); - - return new CurrentMembersResponse(responses); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java b/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java deleted file mode 100644 index c18694393..000000000 --- a/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package server.haengdong.presentation.response; - -import server.haengdong.application.response.EventDetailAppResponse; - -public record EventDetailResponse(String eventName) { - - public static EventDetailResponse of(EventDetailAppResponse response) { - return new EventDetailResponse(response.eventName()); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/response/EventResponse.java b/server/src/main/java/server/haengdong/presentation/response/EventResponse.java deleted file mode 100644 index 506f5e814..000000000 --- a/server/src/main/java/server/haengdong/presentation/response/EventResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package server.haengdong.presentation.response; - -import server.haengdong.application.response.EventAppResponse; - -public record EventResponse(String eventId) { - - public static EventResponse of(EventAppResponse eventAppResponse) { - return new EventResponse(eventAppResponse.token()); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java deleted file mode 100644 index 0ea409202..000000000 --- a/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package server.haengdong.presentation.response; - -import server.haengdong.application.response.MemberBillReportAppResponse; - -public record MemberBillReportResponse(String name, Long price) { - - public static MemberBillReportResponse of(MemberBillReportAppResponse memberBillReportAppResponse) { - return new MemberBillReportResponse(memberBillReportAppResponse.name(), memberBillReportAppResponse.price()); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java deleted file mode 100644 index d350c4009..000000000 --- a/server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java +++ /dev/null @@ -1,15 +0,0 @@ -package server.haengdong.presentation.response; - -import java.util.List; -import server.haengdong.application.response.MemberBillReportAppResponse; - -public record MemberBillReportsResponse(List<MemberBillReportResponse> reports) { - - public static MemberBillReportsResponse of(List<MemberBillReportAppResponse> memberBillReports) { - List<MemberBillReportResponse> reports = memberBillReports.stream() - .map(MemberBillReportResponse::of) - .toList(); - - return new MemberBillReportsResponse(reports); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/response/StepResponse.java b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java deleted file mode 100644 index a8f3877ef..000000000 --- a/server/src/main/java/server/haengdong/presentation/response/StepResponse.java +++ /dev/null @@ -1,57 +0,0 @@ -package server.haengdong.presentation.response; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import server.haengdong.application.response.ActionAppResponse; - -public record StepResponse( - List<ActionsResponse> steps -) { - - public static StepResponse of(List<ActionAppResponse> actions) { - if (actions.isEmpty()) { - return new StepResponse(List.of()); - } - List<ActionsResponse> actionsResponse = new ArrayList<>(); - Set<String> members = new HashSet<>(); - ActionAppResponse firstAction = getFirstAction(actions); - List<ActionAppResponse> group = new ArrayList<>(); - group.add(firstAction); - String currentActionType = firstAction.actionTypeName(); - members.add(firstAction.name()); - - for (int i = 1; i < actions.size(); i++) { - ActionAppResponse action = actions.get(i); - String typeName = action.actionTypeName(); - if (currentActionType.equals(typeName)) { - if (typeName.equals("IN")) { - members.add(action.name()); - } - if (typeName.equals("OUT")) { - members.remove(action.name()); - } - group.add(action); - continue; - } - actionsResponse.add(ActionsResponse.of(group, members)); - currentActionType = typeName; - group.clear(); - if (typeName.equals("IN")) { - members.add(action.name()); - } - if (typeName.equals("OUT")) { - members.remove(action.name()); - } - group.add(action); - } - actionsResponse.add(ActionsResponse.of(group, members)); - - return new StepResponse(actionsResponse); - } - - private static ActionAppResponse getFirstAction(List<ActionAppResponse> actions) { - return actions.get(0); - } -} diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml deleted file mode 100644 index faf7a36f1..000000000 --- a/server/src/main/resources/application.yml +++ /dev/null @@ -1,31 +0,0 @@ -spring: - datasource: - driver-class-name: org.h2.Driver - url: jdbc:h2:mem:database - username: sa - password: - - h2: - console: - enabled: true - path: /h2-console - - jpa: - hibernate: - ddl-auto: create - properties: - hibernate: - format_sql: true - show-sql: true - -cors: - max-age: 3600 - allowed-origins: http://localhost:3000, https://haengdong.pro, https://dev.haengdong.pro, https://app.haengdong.pro - ---- - -spring: - config: - import: classpath:config/application-dev.yml - activate: - on-profile: dev diff --git a/server/src/main/resources/config b/server/src/main/resources/config deleted file mode 160000 index c12697b65..000000000 --- a/server/src/main/resources/config +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c12697b650b8a8adf27fd66377f6e62bb6b8a49d diff --git a/server/src/test/java/server/haengdong/application/ActionServiceTest.java b/server/src/test/java/server/haengdong/application/ActionServiceTest.java deleted file mode 100644 index ac2dc4f4f..000000000 --- a/server/src/test/java/server/haengdong/application/ActionServiceTest.java +++ /dev/null @@ -1,79 +0,0 @@ -package server.haengdong.application; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.assertj.core.api.Assertions.tuple; -import static server.haengdong.domain.action.MemberActionStatus.IN; -import static server.haengdong.domain.action.MemberActionStatus.OUT; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import server.haengdong.application.response.MemberBillReportAppResponse; -import server.haengdong.domain.action.Action; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.BillActionRepository; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionRepository; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -@SpringBootTest -class ActionServiceTest { - - @Autowired - private ActionService actionService; - - @Autowired - private EventRepository eventRepository; - - @Autowired - private BillActionRepository billActionRepository; - - @Autowired - private MemberActionRepository memberActionRepository; - - @DisplayName("참여자별 정산 현황을 조회한다.") - @Test - void getMemberBillReports() { - String token = "tOkEn1"; - Event event = new Event("행동대장", token); - Event savedEvent = eventRepository.save(event); - List<MemberAction> memberActions = List.of( - new MemberAction(new Action(savedEvent, 1L), "소하", IN, 1L), - new MemberAction(new Action(savedEvent, 2L), "감자", IN, 1L), - new MemberAction(new Action(savedEvent, 3L), "쿠키", IN, 1L), - new MemberAction(new Action(savedEvent, 5L), "감자", OUT, 2L) - ); - List<BillAction> billActions = List.of( - new BillAction(new Action(savedEvent, 4L), "뽕족", 60_000L), - new BillAction(new Action(savedEvent, 6L), "인생맥주", 40_000L), - new BillAction(new Action(savedEvent, 7L), "인생네컷", 20_000L) - ); - memberActionRepository.saveAll(memberActions); - billActionRepository.saveAll(billActions); - - List<MemberBillReportAppResponse> responses = actionService.getMemberBillReports(token); - - assertThat(responses) - .hasSize(3) - .extracting(MemberBillReportAppResponse::name, MemberBillReportAppResponse::price) - .containsExactlyInAnyOrder( - tuple("감자", 20_000L), - tuple("쿠키", 50_000L), - tuple("소하", 50_000L) - ); - } - - @DisplayName("존재하지 않는 이벤트의 참여자별 정산 현황을 조회하는 경우 예외가 발생한다.") - @Test - void getMemberBillReports1() { - assertThatThrownBy(() -> actionService.getMemberBillReports("invalid token")) - .isInstanceOf(HaengdongException.class) - .hasMessage(HaengdongErrorCode.NOT_FOUND_EVENT.getMessage()); - } -} diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java deleted file mode 100644 index 195d4bdd9..000000000 --- a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java +++ /dev/null @@ -1,65 +0,0 @@ -package server.haengdong.application; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.assertj.core.api.Assertions.tuple; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import server.haengdong.application.request.BillActionAppRequest; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.action.BillActionRepository; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.exception.HaengdongException; - -@SpringBootTest -class BillActionServiceTest { - - @Autowired - private BillActionService billActionService; - - @Autowired - private EventRepository eventRepository; - - @Autowired - private BillActionRepository billActionRepository; - - @DisplayName("지출 내역을 생성한다.") - @Test - void saveAllBillAction() { - String token = "TOKEN"; - Event event = new Event("감자", token); - Event savedEvent = eventRepository.save(event); - - List<BillActionAppRequest> requests = List.of( - new BillActionAppRequest("뽕족", 10_000L), - new BillActionAppRequest("인생맥주", 15_000L) - ); - - billActionService.saveAllBillAction(token, requests); - - List<BillAction> actions = billActionRepository.findByAction_Event(savedEvent); - - assertThat(actions).extracting(BillAction::getTitle, BillAction::getPrice, BillAction::getSequence) - .containsExactlyInAnyOrder( - tuple("뽕족", 10_000L, 1L), - tuple("인생맥주", 15_000L, 2L) - ); - } - - @DisplayName("이벤트가 존재하지 않으면 지출 내역을 생성할 수 없다.") - @Test - void saveAllBillAction1() { - List<BillActionAppRequest> requests = List.of( - new BillActionAppRequest("뽕족", 10_000L), - new BillActionAppRequest("인생맥주", 15_000L) - ); - - assertThatThrownBy(() -> billActionService.saveAllBillAction("token", requests)) - .isInstanceOf(HaengdongException.class); - } -} diff --git a/server/src/test/java/server/haengdong/application/EventServiceTest.java b/server/src/test/java/server/haengdong/application/EventServiceTest.java deleted file mode 100644 index 5a3e8bce3..000000000 --- a/server/src/test/java/server/haengdong/application/EventServiceTest.java +++ /dev/null @@ -1,110 +0,0 @@ -package server.haengdong.application; - - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.tuple; -import static org.mockito.BDDMockito.given; - -import java.util.List; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import server.haengdong.application.request.EventAppRequest; -import server.haengdong.application.response.ActionAppResponse; -import server.haengdong.application.response.EventAppResponse; -import server.haengdong.application.response.EventDetailAppResponse; -import server.haengdong.domain.action.Action; -import server.haengdong.domain.action.ActionRepository; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.BillActionRepository; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionRepository; -import server.haengdong.domain.action.MemberActionStatus; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.domain.event.EventTokenProvider; - -@SpringBootTest -class EventServiceTest { - - @Autowired - private EventService eventService; - - @MockBean - private EventTokenProvider eventTokenProvider; - - @Autowired - private EventRepository eventRepository; - - @Autowired - private ActionRepository actionRepository; - - @Autowired - private BillActionRepository billActionRepository; - - @Autowired - private MemberActionRepository memberActionRepository; - - @AfterEach - void tearDown() { - billActionRepository.deleteAllInBatch(); - memberActionRepository.deleteAllInBatch(); - actionRepository.deleteAllInBatch(); - eventRepository.deleteAllInBatch(); - } - - @DisplayName("행사를 생성한다") - @Test - void saveEventTest() { - EventAppRequest request = new EventAppRequest("test"); - given(eventTokenProvider.createToken()).willReturn("TOKEN"); - - EventAppResponse response = eventService.saveEvent(request); - - assertThat(response.token()).isEqualTo("TOKEN"); - } - - @DisplayName("토큰으로 행사를 조회한다.") - @Test - void findEventTest() { - String token = "TOKEN"; - Event event = new Event("행동대장 회식", token); - eventRepository.save(event); - - EventDetailAppResponse eventDetailAppResponse = eventService.findEvent(token); - - assertThat(eventDetailAppResponse.eventName()).isEqualTo("행동대장 회식"); - } - - @DisplayName("행사에 속한 모든 액션을 조회한다.") - @Test - void findActionsTest() { - Event event = new Event("행동대장 회식", "웨디_토큰"); - Action action = new Action(event, 1L); - MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); - Action action1 = new Action(event, 2L); - MemberAction memberAction1 = new MemberAction(action1, "쿠키", MemberActionStatus.IN, 1L); - Action action2 = new Action(event, 3L); - BillAction billAction = new BillAction(action2, "뽕나무쟁이족발", 30000L); - eventRepository.save(event); - memberActionRepository.saveAll(List.of(memberAction, memberAction1)); - billActionRepository.save(billAction); - - List<ActionAppResponse> actionAppResponses = eventService.findActions("웨디_토큰"); - - assertThat(actionAppResponses).hasSize(3) - .extracting(ActionAppResponse::actionId, - ActionAppResponse::name, - ActionAppResponse::price, - ActionAppResponse::sequence, - ActionAppResponse::actionTypeName) - .containsExactly( - tuple(1L, "토다리", null, 1L, "IN"), - tuple(2L, "쿠키", null, 2L, "IN"), - tuple(3L, "뽕나무쟁이족발", 30000L, 3L, "BILL") - ); - } -} diff --git a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java deleted file mode 100644 index 40bee2ff6..000000000 --- a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java +++ /dev/null @@ -1,217 +0,0 @@ -package server.haengdong.application; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.assertj.core.api.Assertions.tuple; - -import java.util.List; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import server.haengdong.application.request.MemberActionSaveAppRequest; -import server.haengdong.application.request.MemberActionsSaveAppRequest; -import server.haengdong.domain.action.Action; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionStatus; -import server.haengdong.domain.action.ActionRepository; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.domain.action.MemberActionRepository; -import server.haengdong.exception.HaengdongException; - -@SpringBootTest -class MemberActionFactoryTest { - - @Autowired - private MemberActionFactory memberActionFactory; - - @Autowired - private MemberActionRepository memberActionRepository; - - @Autowired - private ActionRepository actionRepository; - - @Autowired - private EventRepository eventRepository; - - @AfterEach - void tearDown() { - memberActionRepository.deleteAllInBatch(); - actionRepository.deleteAllInBatch(); - eventRepository.deleteAllInBatch(); - } - - @DisplayName("이전 멤버 액션이 시퀀스 기준으로 정렬되지 않은 상태에서 새로운 멤버 액션 요청을 검증한다.") - @Test - void createMemberActionsTest() { - Event event = eventRepository.save(new Event("우당탕탕 행동대장 백엔드 회식", "토다리_토큰")); - Action action1 = new Action(event, 1L); - Action action2 = new Action(event, 2L); - MemberAction memberAction1 = new MemberAction(action1, "토다리", MemberActionStatus.IN, 1L); - MemberAction memberAction2 = new MemberAction(action2, "토다리", MemberActionStatus.OUT, 2L); - memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); - List<MemberAction> unorderedMemberActions = List.of(memberAction2, memberAction1); - Action startAction = new Action(event, 3L); - - assertThatThrownBy(() -> memberActionFactory.createMemberActions(request, unorderedMemberActions, startAction)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("인원 변동 액션을 생성한다.") - @Test - void createMemberActionsTest1() { - Event event = eventRepository.save(new Event("우당탕탕 행동대장 백엔드 회식", "토다리_토큰")); - Action action = new Action(event, 1L); - MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); - memberActionRepository.save(memberAction); - - MemberActionsSaveAppRequest memberActionsSaveAppRequest = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); - Action startAction = new Action(event, 2L); - - List<MemberAction> memberActions = memberActionFactory.createMemberActions(memberActionsSaveAppRequest, - List.of(memberAction), startAction); - - assertThat(memberActions).hasSize(1) - .extracting(MemberAction::getAction, MemberAction::getMemberName, MemberAction::getStatus) - .containsExactly( - tuple(startAction, "토다리", MemberActionStatus.OUT) - ); - } - - @DisplayName("현재 행사에 참여 중인 경우에 퇴장할 수 있다.") - @Test - void createMemberActionsTest2() { - Event event = eventRepository.save(new Event("test", "TOKEN")); - Action action = new Action(event, 1L); - MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); - memberActionRepository.save(memberAction); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); - Action startAction = new Action(event, 2L); - - assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) - .doesNotThrowAnyException(); - } - - @DisplayName("행사에서 퇴장한 경우에 입장할 수 있다.") - @Test - void createMemberActionsTest3() { - Event event = eventRepository.save(new Event("test", "TOKEN")); - Action action1 = new Action(event, 1L); - MemberAction memberAction1 = new MemberAction(action1, "토다리", MemberActionStatus.IN, 1L); - memberActionRepository.save(memberAction1); - Action action2 = new Action(event, 2L); - MemberAction memberAction2 = new MemberAction(action2, "토다리", MemberActionStatus.OUT, 2L); - memberActionRepository.save(memberAction2); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("토다리", "IN"))); - Action startAction = new Action(event, 3L); - - assertThatCode( - () -> memberActionFactory.createMemberActions(request, List.of(memberAction1, memberAction2), - startAction)) - .doesNotThrowAnyException(); - } - - @DisplayName("행사에 입장한 적 없는 경우에 입장할 수 있다.") - @Test - void createMemberActionsTest4() { - Event event = eventRepository.save(new Event("test", "TOKEN")); - Action action = new Action(event, 1L); - MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); - memberActionRepository.save(memberAction); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); - Action startAction = new Action(event, 2L); - - assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) - .doesNotThrowAnyException(); - } - - @DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다.") - @Test - void createMemberActionTest5() { - Event event = eventRepository.save(new Event("test", "TOKEN")); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("쿠키", "OUT"))); - Action startAction = new Action(event, 2L); - - assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(), startAction)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("행사에 이미 참여 중인 경우 다시 입장할 수 없다.") - @Test - void createMemberActionTest6() { - Event event = eventRepository.save(new Event("test", "TOKEN")); - Action action = new Action(event, 1L); - MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); - memberActionRepository.save(memberAction); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); - Action startAction = new Action(event, 2L); - - assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("한 명의 사용자는 동시에 여러 번 입장할 수 없다.") - @Test - void createMemberActionTest7() { - Event event = eventRepository.save(new Event("test", "TOKEN")); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("쿠키", "IN"), - new MemberActionSaveAppRequest("쿠키", "IN"))); - Action startAction = new Action(event, 1L); - - assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(), startAction)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("한 명의 사용자는 동시에 여러 번 퇴장할 수 없다.") - @Test - void createMemberActionTest8() { - Event event = eventRepository.save(new Event("test", "TOKEN")); - Action action = new Action(event, 1L); - MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); - memberActionRepository.save(memberAction); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("쿠키", "OUT"), - new MemberActionSaveAppRequest("쿠키", "OUT"))); - Action startAction = new Action(event, 2L); - - assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("한 명의 사용자는 입장과 퇴장을 동시에 할 수 없다.") - @Test - void createMemberActionTest9() { - Event event = eventRepository.save(new Event("test", "TOKEN")); - Action action = new Action(event, 1L); - MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); - memberActionRepository.save(memberAction); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("쿠키", "IN"), - new MemberActionSaveAppRequest("쿠키", "OUT"))); - Action startAction = new Action(event, 2L); - - assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) - .isInstanceOf(HaengdongException.class); - } -} diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java deleted file mode 100644 index 7212e300d..000000000 --- a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java +++ /dev/null @@ -1,92 +0,0 @@ -package server.haengdong.application; - -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static server.haengdong.domain.action.MemberActionStatus.IN; -import static server.haengdong.domain.action.MemberActionStatus.OUT; - -import java.util.List; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import server.haengdong.application.request.MemberActionSaveAppRequest; -import server.haengdong.application.request.MemberActionsSaveAppRequest; -import server.haengdong.domain.action.Action; -import server.haengdong.domain.action.ActionRepository; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionRepository; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.exception.HaengdongException; - -@SpringBootTest -class MemberActionServiceTest { - - @Autowired - private MemberActionService memberActionService; - - @Autowired - private MemberActionRepository memberActionRepository; - - @Autowired - private EventRepository eventRepository; - - @Autowired - private ActionRepository actionRepository; - - @AfterEach - void tearDown() { - memberActionRepository.deleteAllInBatch(); - actionRepository.deleteAllInBatch(); - eventRepository.deleteAllInBatch(); - } - - @DisplayName("현재 행사에 참여하고 있는 경우에 나갈 수 있다.") - @Test - void saveMemberActionTest() { - Event event = eventRepository.save(new Event("test", "TOKEN")); - Action action = new Action(event, 1L); - MemberAction memberAction = new MemberAction(action, "망쵸", IN, 1L); - memberActionRepository.save(memberAction); - - assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("망쵸", "OUT"))))) - .doesNotThrowAnyException(); - } - - @DisplayName("행사에서 퇴장한 경우에 입장할 수 있다.") - @Test - void saveMemberActionTest1() { - Event event = eventRepository.save(new Event("test", "TOKEN")); - Action actionOne = new Action(event, 1L); - MemberAction memberActionOne = new MemberAction(actionOne, "망쵸", IN, 1L); - memberActionRepository.save(memberActionOne); - - Action actionTwo = new Action(event, 2L); - MemberAction memberActionTwo = new MemberAction(actionTwo, "망쵸", OUT, 1L); - memberActionRepository.save(memberActionTwo); - - assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("망쵸", "IN"))))) - .doesNotThrowAnyException(); - } - - @DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다.") - @Test - void saveMemberActionTest2() { - MemberActionsSaveAppRequest appRequest = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("TOKEN", "OUT"))); - - assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", appRequest)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("이벤트가 없으면 현재 참여 인원을 조회할 수 없다.") - @Test - void getCurrentMembers() { - assertThatThrownBy(() -> memberActionService.getCurrentMembers("token")) - .isInstanceOf(HaengdongException.class); - } -} diff --git a/server/src/test/java/server/haengdong/domain/action/ActionTest.java b/server/src/test/java/server/haengdong/domain/action/ActionTest.java deleted file mode 100644 index 199a4f628..000000000 --- a/server/src/test/java/server/haengdong/domain/action/ActionTest.java +++ /dev/null @@ -1,30 +0,0 @@ -package server.haengdong.domain.action; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import server.haengdong.domain.event.Event; - -class ActionTest { - - @DisplayName("액션의 초기 순서번호는 1이다.") - @Test - void createFirst() { - Event event = new Event("name", "token"); - Action action = Action.createFirst(event); - - assertThat(action.getSequence()).isOne(); - } - - @DisplayName("현재 액션의 다음 액션의 순서는 1만큼 증가한다.") - @Test - void next() { - Event event = new Event("name", "token"); - Action action = new Action(event, 2L); - - Action nextAction = action.next(); - - assertThat(nextAction.getSequence()).isEqualTo(3L); - } -} diff --git a/server/src/test/java/server/haengdong/domain/action/BillActionTest.java b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java deleted file mode 100644 index 601ca95d7..000000000 --- a/server/src/test/java/server/haengdong/domain/action/BillActionTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package server.haengdong.domain.action; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.assertAll; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; -import server.haengdong.domain.event.Event; -import server.haengdong.exception.HaengdongException; - -class BillActionTest { - - @DisplayName("지출 내역 제목의 앞뒤 공백을 제거한 길이가 2 ~ 30자가 아니면 지출을 생성할 수 없다.") - @ParameterizedTest - @ValueSource(strings = {" 감 ", "", " ", "1234567890123456789012345678901"}) - void validateTitle(String title) { - Event event = new Event("name", "token"); - Action action = new Action(event, 1L); - Long price = 100L; - - assertThatThrownBy(() -> new BillAction(action, title, price)) - .isInstanceOf(HaengdongException.class) - .hasMessage("앞뒤 공백을 제거한 지출 내역 제목은 2 ~ 30자여야 합니다."); - } - - @DisplayName("금액이 10,000,000 이하의 자연수가 아니면 지출을 생성할 수 없다.") - @ParameterizedTest - @ValueSource(longs = {0, 10_000_001, 20_000_000}) - void validatePrice(long price) { - Event event = new Event("name", "token"); - Action action = new Action(event, 1L); - String title = "title"; - - assertThatThrownBy(() -> new BillAction(action, title, price)) - .isInstanceOf(HaengdongException.class) - .hasMessage("지출 금액은 10,000,000 이하의 자연수여야 합니다."); - } - - @DisplayName("지출 내역을 올바르게 생성한다.") - @Test - void createBillAction() { - Event event = new Event("name", "token"); - Action action = new Action(event, 1L); - String title = "title"; - Long price = 1_000L; - - BillAction billAction = new BillAction(action, title, price); - - assertAll( - () -> assertThat(billAction.getAction()).isEqualTo(action), - () -> assertThat(billAction.getTitle()).isEqualTo(title), - () -> assertThat(billAction.getPrice()).isEqualTo(price) - ); - } -} diff --git a/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java b/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java deleted file mode 100644 index 389ca70c1..000000000 --- a/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package server.haengdong.domain.action; - -import static org.assertj.core.api.Assertions.assertThat; -import static server.haengdong.domain.action.MemberActionStatus.IN; -import static server.haengdong.domain.action.MemberActionStatus.OUT; - -import java.util.List; -import java.util.Set; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import server.haengdong.domain.event.Event; - -class CurrentMembersTest { - - @DisplayName("인원 변동 이력으로 현재 참여 인원을 계산한다.") - @Test - void of() { - Event event = new Event("test", "TOKEN"); - List<MemberAction> memberActions = List.of( - new MemberAction(new Action(event, 1L), "망쵸", IN, 1L), - new MemberAction(new Action(event, 2L), "백호", IN, 1L), - new MemberAction(new Action(event, 3L), "백호", OUT, 1L), - new MemberAction(new Action(event, 4L), "웨디", IN, 1L) - ); - - CurrentMembers currentMembers = CurrentMembers.of(memberActions); - - assertThat(currentMembers.getMembers()) - .containsExactlyInAnyOrder("망쵸", "웨디"); - } - - @DisplayName("인원 변동 액션의 상태가 IN이면 현재 인원에 추가한다.") - @Test - void addMemberAction1() { - CurrentMembers currentMembers = new CurrentMembers(); - Event event = new Event("이벤트", "token"); - MemberAction memberAction = new MemberAction(new Action(event, 1L), "웨디", IN, 1L); - - CurrentMembers addedCurrentMembers = currentMembers.addMemberAction(memberAction); - Set<String> members = addedCurrentMembers.getMembers(); - - assertThat(members).hasSize(1) - .containsExactly("웨디"); - } - - @DisplayName("인원 변동 액션의 상태가 OUT이면 현재 인원에서 제외한다.") - @Test - void addMemberAction2() { - Event event = new Event("이벤트", "token"); - MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "웨디", IN, 1L); - CurrentMembers currentMembers = new CurrentMembers().addMemberAction(memberAction1); - MemberAction memberAction2 = new MemberAction(new Action(event, 1L), "웨디", OUT, 1L); - - CurrentMembers addedCurrentMembers = currentMembers.addMemberAction(memberAction2); - - assertThat(addedCurrentMembers.getMembers()).hasSize(0); - } -} diff --git a/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java b/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java deleted file mode 100644 index 9ad27d5bc..000000000 --- a/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package server.haengdong.domain.action; - -import static org.assertj.core.api.Assertions.assertThat; -import static server.haengdong.domain.action.MemberActionStatus.IN; -import static server.haengdong.domain.action.MemberActionStatus.OUT; - -import java.util.List; -import java.util.Map; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import server.haengdong.domain.event.Event; - -class MemberBillReportTest { - - @DisplayName("액션 목록으로 참가자 정산 리포트를 생성한다.") - @Test - void createByActions() { - String token = "TOK2N"; - Event event = new Event("행동대장", token); - List<BillAction> billActions = List.of( - new BillAction(new Action(event, 4L), "뽕족", 60_000L), - new BillAction(new Action(event, 6L), "인생맥주", 40_000L), - new BillAction(new Action(event, 7L), "인생네컷", 20_000L) - ); - List<MemberAction> memberActions = List.of( - new MemberAction(new Action(event, 1L), "소하", IN, 1L), - new MemberAction(new Action(event, 2L), "감자", IN, 1L), - new MemberAction(new Action(event, 3L), "쿠키", IN, 1L), - new MemberAction(new Action(event, 5L), "감자", OUT, 2L) - ); - - MemberBillReport memberBillReport = MemberBillReport.createByActions(billActions, memberActions); - - assertThat(memberBillReport.getReports()) - .containsAllEntriesOf( - Map.of( - "감자", 20_000L, - "쿠키", 50_000L, - "소하", 50_000L - ) - ); - } -} diff --git a/server/src/test/java/server/haengdong/domain/event/EventTest.java b/server/src/test/java/server/haengdong/domain/event/EventTest.java deleted file mode 100644 index 98f6c7050..000000000 --- a/server/src/test/java/server/haengdong/domain/event/EventTest.java +++ /dev/null @@ -1,37 +0,0 @@ -package server.haengdong.domain.event; - -import static org.assertj.core.api.Assertions.assertThatCode; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; -import server.haengdong.exception.HaengdongException; - -class EventTest { - - @DisplayName("공백 문자가 연속되지 않고, 이름이 2자 이상 20자 이하인 행사를 생성하면 예외가 발생하지 않는다.") - @ParameterizedTest - @ValueSource(strings = {"12", "12345678901234567890", "공 백", " 공백", "공백 ", " 공 백 "}) - void createSuccessTest(String eventName) { - assertThatCode(() -> new Event(eventName, "TEST_TOKEN")) - .doesNotThrowAnyException(); - } - - @DisplayName("공백 문자가 연속되면 예외가 발생한다.") - @ParameterizedTest - @ValueSource(strings = {" 공백", "공백 ", "공백 연속", "공 백"}) - void createFailTest1(String eventName) { - assertThatCode(() -> new Event(eventName, "TEST_TOKEN")) - .isInstanceOf(HaengdongException.class) - .hasMessage(String.format("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s", eventName)); - } - - @DisplayName("이름이 2자 미만이거나 20자 초과인 경우 예외가 발생한다.") - @ParameterizedTest - @ValueSource(strings = {"", " ", "123456789012345678901"}) - void createFilTest2(String eventName) { - assertThatCode(() -> new Event(eventName, "TEST_TOKEN")) - .isInstanceOf(HaengdongException.class) - .hasMessage(String.format("행사 이름은 2자 이상 20자 이하만 입력 가능합니다. 입력한 이름 길이 : %d", eventName.length())); - } -} diff --git a/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java deleted file mode 100644 index 739ac4962..000000000 --- a/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java +++ /dev/null @@ -1,49 +0,0 @@ -package server.haengdong.presentation; - -import static org.hamcrest.Matchers.equalTo; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers; -import server.haengdong.application.ActionService; -import server.haengdong.application.response.MemberBillReportAppResponse; - -@WebMvcTest(ActionController.class) -class ActionControllerTest { - - @Autowired - private MockMvc mockMvc; - - @MockBean - private ActionService actionService; - - @DisplayName("참여자별 정산 현황을 조회한다.") - @Test - void getMemberBillReports() throws Exception { - List<MemberBillReportAppResponse> memberBillReportAppResponses = List.of( - new MemberBillReportAppResponse("소하", 20_000L), new MemberBillReportAppResponse("토다리", 200_000L)); - - given(actionService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); - - mockMvc.perform(get("/api/events/{token}/actions/reports", "token") - .accept(MediaType.APPLICATION_JSON)) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].name").value(equalTo("소하"))) - .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].price").value(equalTo(20_000))) - .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].name").value(equalTo("토다리"))) - .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].price").value(equalTo(200_000))); - - } -} diff --git a/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java deleted file mode 100644 index 8bf2b292f..000000000 --- a/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java +++ /dev/null @@ -1,69 +0,0 @@ -package server.haengdong.presentation; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import com.fasterxml.jackson.databind.ObjectMapper; -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MockMvc; -import server.haengdong.application.BillActionService; -import server.haengdong.presentation.request.BillActionSaveRequest; -import server.haengdong.presentation.request.BillActionsSaveRequest; - -@WebMvcTest(BillActionController.class) -class BillActionControllerTest { - - @Autowired - private MockMvc mockMvc; - - @Autowired - private ObjectMapper objectMapper; - - @MockBean - private BillActionService billActionService; - - @DisplayName("지출 내역을 생성한다.") - @Test - void saveAllBillAction() throws Exception { - BillActionsSaveRequest request = new BillActionsSaveRequest( - List.of( - new BillActionSaveRequest("뽕족", 10_000L), - new BillActionSaveRequest("인생맥주", 10_000L) - ) - ); - String requestBody = objectMapper.writeValueAsString(request); - String token = "TOKEN"; - - mockMvc.perform(post("/api/events/{token}/actions/bills", token) - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) - .andDo(print()) - .andExpect(status().isOk()); - } - - @DisplayName("title이 비어 있는 경우 지출 내역을 생성할 수 없다.") - @Test - void saveAllBillAction1() throws Exception { - BillActionsSaveRequest request = new BillActionsSaveRequest( - List.of( - new BillActionSaveRequest("", 10_000L), - new BillActionSaveRequest("인생맥주", 10_000L) - ) - ); - String requestBody = objectMapper.writeValueAsString(request); - String token = "TOKEN"; - - mockMvc.perform(post("/api/events/{token}/actions/bills", token) - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) - .andDo(print()) - .andExpect(status().isBadRequest()); - } -} diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java deleted file mode 100644 index 55a48630f..000000000 --- a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java +++ /dev/null @@ -1,66 +0,0 @@ -package server.haengdong.presentation; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MockMvc; -import server.haengdong.application.EventService; -import server.haengdong.application.request.EventAppRequest; -import server.haengdong.application.response.EventAppResponse; -import server.haengdong.application.response.EventDetailAppResponse; -import server.haengdong.presentation.request.EventSaveRequest; - -@WebMvcTest(EventController.class) -class EventControllerTest { - - @Autowired - private MockMvc mockMvc; - - @Autowired - private ObjectMapper objectMapper; - - @MockBean - private EventService eventService; - - @DisplayName("이벤트를 생성한다.") - @Test - void saveEvent() throws Exception { - EventSaveRequest eventSaveRequest = new EventSaveRequest("토다리"); - String requestBody = objectMapper.writeValueAsString(eventSaveRequest); - String token = "TOKEN"; - EventAppResponse eventAppResponse = new EventAppResponse(token); - given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); - - mockMvc.perform(post("/api/events") - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.eventId").value("TOKEN")); - } - - @DisplayName("토큰으로 행사를 조회한다.") - @Test - void findEventTest() throws Exception { - String token = "TOKEN"; - EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식"); - given(eventService.findEvent(token)).willReturn(eventDetailAppResponse); - - mockMvc.perform(get("/api/events/" + token)) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.eventName").value("행동대장 회식")); - } -} diff --git a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java deleted file mode 100644 index ad8787cc6..000000000 --- a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java +++ /dev/null @@ -1,67 +0,0 @@ -package server.haengdong.presentation; - -import static org.hamcrest.Matchers.equalTo; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import com.fasterxml.jackson.databind.ObjectMapper; -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers; -import server.haengdong.application.MemberActionService; -import server.haengdong.application.response.CurrentMemberAppResponse; -import server.haengdong.presentation.request.MemberActionsSaveRequest; - -@WebMvcTest(MemberActionController.class) -class MemberActionControllerTest { - - @Autowired - private MockMvc mockMvc; - - @Autowired - private ObjectMapper objectMapper; - - @MockBean - private MemberActionService memberActionService; - - @DisplayName("참여자 행동을 추가한다.") - @Test - void saveMemberActionTest() throws Exception { - MemberActionsSaveRequest memberActionsSaveRequest = new MemberActionsSaveRequest( - List.of("웨디", "소하", "토다리", "쿠키"), "IN"); - - String requestBody = objectMapper.writeValueAsString(memberActionsSaveRequest); - - mockMvc.perform(post("/api/events/TOKEN/actions/members") - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) - .andDo(print()) - .andExpect(status().isOk()); - } - - @DisplayName("현재 참여 인원을 조회합니다.") - @Test - void getCurrentMembers() throws Exception { - List<CurrentMemberAppResponse> currentMemberAppResponses = List.of( - new CurrentMemberAppResponse("소하"), new CurrentMemberAppResponse("토다리")); - - given(memberActionService.getCurrentMembers(any())).willReturn(currentMemberAppResponses); - - mockMvc.perform(get("/api/events/{token}/members/current", "token") - .accept(MediaType.APPLICATION_JSON)) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$.members[0].name").value(equalTo("소하"))) - .andExpect(MockMvcResultMatchers.jsonPath("$.members[1].name").value(equalTo("토다리"))); - } -} diff --git a/server/src/test/java/server/haengdong/presentation/response/StepResponseTest.java b/server/src/test/java/server/haengdong/presentation/response/StepResponseTest.java deleted file mode 100644 index aac78691c..000000000 --- a/server/src/test/java/server/haengdong/presentation/response/StepResponseTest.java +++ /dev/null @@ -1,57 +0,0 @@ -package server.haengdong.presentation.response; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import java.util.ArrayList; -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import server.haengdong.application.response.ActionAppResponse; -import server.haengdong.application.response.ActionAppResponse.ActionType; - -@SpringBootTest -class StepResponseTest { - - @Autowired - private ObjectMapper objectMapper; - - @DisplayName("") - @Test - void test() throws JsonProcessingException { - List<ActionAppResponse> actionAppResponse = new ArrayList<>(); - - // IN actions - ActionAppResponse actionAppResponse1 = new ActionAppResponse(3L, "망쵸", null, 3L, ActionType.IN); - actionAppResponse.add(actionAppResponse1); - ActionAppResponse actionAppResponse2 = new ActionAppResponse(4L, "백호", null, 4L, ActionType.IN); - actionAppResponse.add(actionAppResponse2); - - // BILL step 1 - ActionAppResponse actionAppResponse3 = new ActionAppResponse(1L, "감자탕", 10000L, 1L, ActionType.BILL); - actionAppResponse.add(actionAppResponse3); - ActionAppResponse actionAppResponse4 = new ActionAppResponse(2L, "인생네컷", 10000L, 2L, ActionType.BILL); - actionAppResponse.add(actionAppResponse4); - - // IN actions - ActionAppResponse actionAppResponse5 = new ActionAppResponse(5L, "소하", null, 5L, ActionType.IN); - actionAppResponse.add(actionAppResponse5); - ActionAppResponse actionAppResponse6 = new ActionAppResponse(6L, "웨디", null, 6L, ActionType.IN); - actionAppResponse.add(actionAppResponse6); - - // OUT actions - ActionAppResponse actionAppResponse7 = new ActionAppResponse(7L, "망쵸", null, 7L, ActionType.OUT); - actionAppResponse.add(actionAppResponse7); - ActionAppResponse actionAppResponse8 = new ActionAppResponse(8L, "백호", null, 8L, ActionType.OUT); - actionAppResponse.add(actionAppResponse8); - - // BILL step 2 - ActionAppResponse actionAppResponse9 = new ActionAppResponse(9L, "노래방", 20000L, 10L, ActionType.BILL); - actionAppResponse.add(actionAppResponse9); - - // StepResponse creation - StepResponse stepResponse = StepResponse.of(actionAppResponse); - System.out.println("stepResponse = " + stepResponse); - } -} diff --git a/server/src/test/resources/application.yml b/server/src/test/resources/application.yml deleted file mode 100644 index 2d02b2712..000000000 --- a/server/src/test/resources/application.yml +++ /dev/null @@ -1,18 +0,0 @@ -spring: - h2: - console: - enabled: true - path: /h2-console - datasource: - url: jdbc:h2:mem:database - jpa: - defer-datasource-initialization: true - show-sql: true - properties: - hibernate: - format_sql: true - hibernate: - ddl-auto: create-drop -cors: - max-age: 3600 - allowed-origins: http://localhost:8080 From 3b5e73dcc7e7daba5513048669469af85b07a138 Mon Sep 17 00:00:00 2001 From: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> Date: Mon, 29 Jul 2024 19:04:17 +0900 Subject: [PATCH 103/178] =?UTF-8?q?chore:=20server=20directory=20=EB=B3=B5?= =?UTF-8?q?=EA=B5=AC=20(#150)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/.gitignore | 244 +++++++++++++++++ server/Dockerfile | 9 + server/build.gradle | 40 +++ server/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43453 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + server/gradlew | 249 ++++++++++++++++++ server/gradlew.bat | 92 +++++++ server/settings.gradle | 1 + .../haengdong/HaengdongApplication.java | 13 + .../haengdong/application/ActionService.java | 37 +++ .../application/BillActionService.java | 44 ++++ .../haengdong/application/EventService.java | 91 +++++++ .../application/MemberActionFactory.java | 82 ++++++ .../application/MemberActionService.java | 60 +++++ .../request/BillActionAppRequest.java | 14 + .../application/request/EventAppRequest.java | 10 + .../request/MemberActionSaveAppRequest.java | 12 + .../request/MemberActionsSaveAppRequest.java | 6 + .../response/ActionAppResponse.java | 54 ++++ .../response/CurrentMemberAppResponse.java | 10 + .../response/EventAppResponse.java | 10 + .../response/EventDetailAppResponse.java | 10 + .../response/MemberBillReportAppResponse.java | 4 + .../server/haengdong/config/WebConfig.java | 27 ++ .../haengdong/domain/action/Action.java | 42 +++ .../domain/action/ActionRepository.java | 21 ++ .../haengdong/domain/action/BillAction.java | 70 +++++ .../domain/action/BillActionRepository.java | 14 + .../domain/action/CurrentMembers.java | 66 +++++ .../haengdong/domain/action/MemberAction.java | 62 +++++ .../domain/action/MemberActionRepository.java | 15 ++ .../domain/action/MemberActionStatus.java | 19 ++ .../domain/action/MemberBillReport.java | 75 ++++++ .../domain/action/MemberGroupIdProvider.java | 11 + .../server/haengdong/domain/event/Event.java | 54 ++++ .../domain/event/EventRepository.java | 11 + .../haengdong/domain/event/EventStep.java | 28 ++ .../domain/event/EventTokenProvider.java | 12 + .../haengdong/exception/ErrorResponse.java | 10 + .../exception/GlobalExceptionHandler.java | 43 +++ .../exception/HaengdongErrorCode.java | 24 ++ .../exception/HaengdongException.java | 32 +++ .../presentation/ActionController.java | 26 ++ .../presentation/BillActionController.java | 29 ++ .../presentation/EventController.java | 43 +++ .../presentation/MemberActionController.java | 39 +++ .../request/BillActionSaveRequest.java | 19 ++ .../request/BillActionsSaveRequest.java | 14 + .../request/EventSaveRequest.java | 15 ++ .../request/MemberActionsSaveRequest.java | 22 ++ .../presentation/response/ActionResponse.java | 20 ++ .../response/ActionsResponse.java | 28 ++ .../response/CurrentMemberResponse.java | 10 + .../response/CurrentMembersResponse.java | 15 ++ .../response/EventDetailResponse.java | 10 + .../presentation/response/EventResponse.java | 10 + .../response/MemberBillReportResponse.java | 10 + .../response/MemberBillReportsResponse.java | 15 ++ .../presentation/response/StepResponse.java | 57 ++++ server/src/main/resources/application.yml | 31 +++ .../application/ActionServiceTest.java | 79 ++++++ .../application/BillActionServiceTest.java | 65 +++++ .../application/EventServiceTest.java | 110 ++++++++ .../application/MemberActionFactoryTest.java | 217 +++++++++++++++ .../application/MemberActionServiceTest.java | 92 +++++++ .../haengdong/domain/action/ActionTest.java | 30 +++ .../domain/action/BillActionTest.java | 58 ++++ .../domain/action/CurrentMembersTest.java | 58 ++++ .../domain/action/MemberBillReportTest.java | 43 +++ .../haengdong/domain/event/EventTest.java | 37 +++ .../presentation/ActionControllerTest.java | 49 ++++ .../BillActionControllerTest.java | 69 +++++ .../presentation/EventControllerTest.java | 66 +++++ .../MemberActionControllerTest.java | 67 +++++ .../response/StepResponseTest.java | 57 ++++ server/src/test/resources/application.yml | 18 ++ 76 files changed, 3263 insertions(+) create mode 100644 server/.gitignore create mode 100644 server/Dockerfile create mode 100644 server/build.gradle create mode 100644 server/gradle/wrapper/gradle-wrapper.jar create mode 100644 server/gradle/wrapper/gradle-wrapper.properties create mode 100644 server/gradlew create mode 100644 server/gradlew.bat create mode 100644 server/settings.gradle create mode 100644 server/src/main/java/server/haengdong/HaengdongApplication.java create mode 100644 server/src/main/java/server/haengdong/application/ActionService.java create mode 100644 server/src/main/java/server/haengdong/application/BillActionService.java create mode 100644 server/src/main/java/server/haengdong/application/EventService.java create mode 100644 server/src/main/java/server/haengdong/application/MemberActionFactory.java create mode 100644 server/src/main/java/server/haengdong/application/MemberActionService.java create mode 100644 server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/EventAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/response/ActionAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/EventAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java create mode 100644 server/src/main/java/server/haengdong/config/WebConfig.java create mode 100644 server/src/main/java/server/haengdong/domain/action/Action.java create mode 100644 server/src/main/java/server/haengdong/domain/action/ActionRepository.java create mode 100644 server/src/main/java/server/haengdong/domain/action/BillAction.java create mode 100644 server/src/main/java/server/haengdong/domain/action/BillActionRepository.java create mode 100644 server/src/main/java/server/haengdong/domain/action/CurrentMembers.java create mode 100644 server/src/main/java/server/haengdong/domain/action/MemberAction.java create mode 100644 server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java create mode 100644 server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java create mode 100644 server/src/main/java/server/haengdong/domain/action/MemberBillReport.java create mode 100644 server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java create mode 100644 server/src/main/java/server/haengdong/domain/event/Event.java create mode 100644 server/src/main/java/server/haengdong/domain/event/EventRepository.java create mode 100644 server/src/main/java/server/haengdong/domain/event/EventStep.java create mode 100644 server/src/main/java/server/haengdong/domain/event/EventTokenProvider.java create mode 100644 server/src/main/java/server/haengdong/exception/ErrorResponse.java create mode 100644 server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java create mode 100644 server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java create mode 100644 server/src/main/java/server/haengdong/exception/HaengdongException.java create mode 100644 server/src/main/java/server/haengdong/presentation/ActionController.java create mode 100644 server/src/main/java/server/haengdong/presentation/BillActionController.java create mode 100644 server/src/main/java/server/haengdong/presentation/EventController.java create mode 100644 server/src/main/java/server/haengdong/presentation/MemberActionController.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/ActionResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/CurrentMemberResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/EventResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/StepResponse.java create mode 100644 server/src/main/resources/application.yml create mode 100644 server/src/test/java/server/haengdong/application/ActionServiceTest.java create mode 100644 server/src/test/java/server/haengdong/application/BillActionServiceTest.java create mode 100644 server/src/test/java/server/haengdong/application/EventServiceTest.java create mode 100644 server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java create mode 100644 server/src/test/java/server/haengdong/application/MemberActionServiceTest.java create mode 100644 server/src/test/java/server/haengdong/domain/action/ActionTest.java create mode 100644 server/src/test/java/server/haengdong/domain/action/BillActionTest.java create mode 100644 server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java create mode 100644 server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java create mode 100644 server/src/test/java/server/haengdong/domain/event/EventTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/ActionControllerTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/EventControllerTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/response/StepResponseTest.java create mode 100644 server/src/test/resources/application.yml diff --git a/server/.gitignore b/server/.gitignore new file mode 100644 index 000000000..671ee930b --- /dev/null +++ b/server/.gitignore @@ -0,0 +1,244 @@ +# Created by https://www.toptal.com/developers/gitignore/api/java,intellij,gradle,macos,windows,linux +# Edit at https://www.toptal.com/developers/gitignore?templates=java,intellij,gradle,macos,windows,linux + +### Intellij ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +# Azure Toolkit for IntelliJ plugin +# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij +.idea/**/azureSettings.xml + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### Gradle ### +.gradle +**/build/ +!src/**/build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Avoid ignore Gradle wrappper properties +!gradle-wrapper.properties + +# Cache of project +.gradletasknamecache + +# Eclipse Gradle plugin generated files +# Eclipse Core +.project +# JDT-specific (Eclipse Java Development Tools) +.classpath + +### Gradle Patch ### +# Java heap dump +*.hprof + +# End of https://www.toptal.com/developers/gitignore/api/java,intellij,gradle,macos,windows,linux diff --git a/server/Dockerfile b/server/Dockerfile new file mode 100644 index 000000000..37e37d237 --- /dev/null +++ b/server/Dockerfile @@ -0,0 +1,9 @@ +FROM openjdk:17-jdk-slim + +WORKDIR /app + +COPY /build/libs/*.jar /app/haengdong-0.0.1-SNAPSHOT.jar + +EXPOSE 8080 +ENTRYPOINT ["java"] +CMD ["-Dspring.profiles.active=dev", "-jar", "haengdong-0.0.1-SNAPSHOT.jar"] diff --git a/server/build.gradle b/server/build.gradle new file mode 100644 index 000000000..26f6ec262 --- /dev/null +++ b/server/build.gradle @@ -0,0 +1,40 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.3.1' + id 'io.spring.dependency-management' version '1.1.5' +} + +group = 'server' +version = '0.0.1-SNAPSHOT' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +configurations { + compileOnly { + extendsFrom annotationProcessor + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-validation' + compileOnly 'org.projectlombok:lombok' + runtimeOnly 'com.h2database:h2' + runtimeOnly 'com.mysql:mysql-connector-j' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/server/gradle/wrapper/gradle-wrapper.jar b/server/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..e6441136f3d4ba8a0da8d277868979cfbc8ad796 GIT binary patch literal 43453 zcma&N1CXTcmMvW9vTb(Rwr$&4wr$(C?dmSu>@vG-+vuvg^_??!{yS%8zW-#zn-LkA z5&1^$^{lnmUON?}LBF8_K|(?T0Ra(xUH{($5eN!MR#ZihR#HxkUPe+_R8Cn`RRs(P z_^*#_XlXmGv7!4;*Y%p4nw?{bNp@UZHv1?Um8r6)Fei3p@ClJn0ECfg1hkeuUU@Or zDaPa;U3fE=3L}DooL;8f;P0ipPt0Z~9P0)lbStMS)ag54=uL9ia-Lm3nh|@(Y?B`; zx_#arJIpXH!U{fbCbI^17}6Ri*H<>OLR%c|^mh8+)*h~K8Z<V--Q23O4&HBVn~<)q zmUaP7+TjluBM%#s1Ki#^GurGElkc7{cc6Skz+1nDVk%wAAQYx1^*wA%KSY>!9)DPf zR2h?lbDZQ`p9P;&DQ4F0sur@TMa!Y}S8irn(%d-gi0*WxxCSk*A?3lGh=gcYN?FGl z7D=Js!i~0=u3rox^e<cs4tSN~YA?c-d185$YFNA$Eq1&U{wh#b^OveuKoBPy0oYZ4 zAY2?B=x8yX9}pVM=cLrvugywt!e@Y3lH)i?7fvT*a`O;c)CJQ>O3i@$0=n{K1lPNU zwmfjRVmLOCRfe=seV&P*1Iq=^i`502keY8Uy-WNPwVNNtJFx?IwA<BCEY82WDKJP< zB^CxjFxi=mg*OyI?K3GoDfk;?-K<Z#JoxhYNeEUf896)l%7gL``44}zn)7|Rf;)SC z_EfJr4I+3i(GiHN`R+vHqf}1wXtH?65<wKlxV1BU(#3XgtH<$Fir3S(7QeRA3)u89 zID&66K{&mq$DsB}s&o?H60{cskfh*hvn8hQW#~Q!qM04QtZvx3JEpqeKWE6|+OZW= z(LB7}flr|t7va%>yR<KG!FYzS$bs7qXcpM&wV@~>PZo2<wCq%CszVO$mosTTuv*Mz zOLoi?e^7B~xS22~QW8Rmnt{(AtL<HGi<_P9`0pH;3)@S9Eg`gt2X<om7C^q}pKX|* zTy3X{nOr-xyt4=Qx1IjrzGb!_SyAv^SZcf;air&-;Ua+)5k0z=#R7@UW%)3oEjGA| zZ#DE3px@h1k7w%|4rVIO=0Aid2A%?nBZrupg^_z5J-$$YKeDZ&q8+k7zccb<dc4D; zz}+UYkl_eUNL3PW+reZ6UUB}=sHp~$z%Q}gZ-#ow+ffQIj|A3`B9LO*6%t@)0PV!x ziJ=9fw_>Wo1+S(xF37LJZ~%i)kpFQ3Fw=mXfd@>%+)RpYQLnr}B~~zoof(JVm^^&f zxKV^+3D3$A1G;qh4gPVjhrC8e(VYUHv#dy^)(RoUFM?o%W-EHxufuWf(l*@-l+7vt z=l`qmR56K~F|v<^Pd*p~1_y^P0P^aPC##d8+HqX4IR1gu+7w#~TBFphJxF)T$2WEa zxa?H&6=Qe7d(#tha?_1uQys2KtHQ{)Qco)qwGjrdNL7thd^G5i8Os)CHqc>iOidS} z%nFEDdm=GXBw=yXe1W-ShHHFb?Cc70+$W~z_+}nAoHFYI1MV1wZegw*0y^tC*s%3h zhD3tN8b=Gv&rj}!SUM6|ajSPp*58KR7MPpI{oAJCtY~JECm)*m_x>AZEu>DFgUcby z1Qaw8lU4jZpQ_$;*7RME+gq1Ky<fW-rh4ehZ;%u960Gt5OF)<y$00S=6tVE=%Pt~( z!&BP&2I%`@>SGG#Wql>aL~k9tLrSO()LWn*q&YxHE<sT^`N@Q|)S3y<ZACaLXO56z zncP$~M5K!npWqz?)C50MMw=XqFtDO!3JHI*t-^8Ga&lGPHX2F0pIGdZ3w5ewE+{kf z-&Ygi?@-h(ADD|ljIBw%VHHf1xuQ~}IeIQ5JqlA4#*Nlvd`IfDYzFa?PB=RCcFpZ4 z|HFmPZM=;^DQ_z<IPz$$+yG(H4803QQAA7vQF7;_gv|AD1bH*R-CP3f<<utDpH)Ht zI@{uO12adp{;132YoKPx?C9{&;MtHdHb*0F0;Z~D42}#*l+WD2u?r>uzmwd1?aAtI zBJ>P=&$=l1efe1CDU;`Fd+_;&wI07?V0aAIgc(<VS*?#8Zt!w88FJrjasA1!6>!{a z0Jg6Y=inXc3^n!U0Atk`iCFIQooHqcWhO(qrieUOW8X(x?(RD}iYDLMjSwffH2~tB z)oDgNBLB^AJBM1M^c5HdRx6fBfka`(LD-qrlh5jqH~);#nw|iyp)()xVYak3;Ybik z0j`(+69aK*B>)e_p%=wu8XC&9e{AO4c~O1U`5X9}?0mrd*m$_EUek{R?DNSh(=br# z#Q61gBzEpmy`$pA<eVn3dnmk^xq`=o2)~2c0ywsuTQsC?1WZZehsJYfK@LQ>*6!87 zSDD+=@fTY7<4A?GLqpA?Pb2z$pbCc4B4zL{BeZ?F-8`s$?>*lXXtn*NC61>|*w7J* z$?!iB{6R-0=KFmyp1nnEmLsA-H0a6l+1uaH^g%c(p{iT&YFrbQ$&PRb8Up#X3@Zsk zD^^&LK~111%cqlP%!_gFNa^dTYT?rhkGl}5=fL{a`UViaXWI$k-UcHJwmaH1s=S$4 z%4)PdWJX;hh5UoK?6aWoyLxX&NhNRqKam7tcOkLh{%j3K^4Mgx1@i|Pi&}<^5>hs5 zm8?uOS>%)NzT(%PjVPGa?X%`N2TQCKbeH2l;cTnHiHppPSJ<7y-yEIiC!P*ikl&!B z%+?>VttCOQM@ShFguHVjxX^?mHX^hSaO_;pnyh^v9EumqSZTi+#f&_Vaija0Q-e*| z7ulQj6Fs*bbmsWp{`auM04gGwsYYdNNZcg|ph0OgD>7O}Asn7^<IivRZw`Wa$`V6) zgX@^QL9j}-Od{q5<J*k0+1U=R5+PCYj(U}4VpX+BjfI~+dttS?HJ6uZSGH#H-twTo zaptG40+PAc$fs*zLFkOfGfc+xGs<T?rLGIA%SU7c%jh!E1SNN~*-`ccW8wo4gv2Sj zhify^C(ygi)uGwqXDLqVbH>Z=eI>`$2*v78;sj-}oMoEj&@)9+ycEOo92xSyY344^ z11Hb8^kdOvbf^GNAK++bYioknrpdN>+u8R?JxG=!2Kd9r=YWCOJYXYuM0cOq^FhEd zBg2puKy__7VT3-r*dG4c62Wgxi52EMCQ`bKgf*#*ou(D4-ZN$+m<X+=`m<r!lO%3T zMp}MJd(WDoQ2&6(LClZxpv<vZPPM3Ngkye2VhB=i|B12g5ouw(%`gbWtRq8~sU|o* z$kQ8Jb~6&{ak;r$7@?#t*q9RfAOj=^uAf1z5Y8`N%M`oM@?!~VqN{g%-u$XR1u1Im zGE&AzFpIcER(5jtCPR%RZ)!+|*rU~jZBiOKdqYjO(%yK3Lz;{##(@QEVo>g&7$u!! z-^<eVk1WtrWdvAzoBMHoB$s2RXJCv}%muyVFFJ``?>+Z%;-3IDwqZ|K=ah85OLwkO zKxNBh+4QHh)u9D?MFtpbl)<T1$eOrb4-+U|WDC2BesgFRlgt`klbeQ^1S`7`r+uZ8 zH&U=geA}Si;CUcKvBA&^@<o1GQ7`{1Y(cCHZv|73JIJOvVwLOMZP%Q|)y@^j2e<+z zWVo=#FL!4XNKS~-_1`gw*qi$0j6P7ym_LTvG>us}9+V!D%w9jfAMYEb>%$A;u)rrI zuBudh;5PN}_6J_}l55P3l_)&RMlH{m!)ai-i$g)&*M`eN$XQMw{v^r@-125^RRCF0 z^2>|DxhQw(mtNEI2Kj(;<s2pnue6O@?^QaAp;Ze6z9nX*w}4h7342+0lU$@;Knnve zqqY2Ci=`)@>KblC7x=JlK$@78`O~>V!`|1Lm-^JR$-5pUANAnb(5}B}JGjBsliK4& zk6y(;$e&h)lh2)L=bvZKbvh@>vLlreBdH8No2>$#%_Wp1U0N7Ank!6$dFSi#xzh|( zRi{U<eziQYNZ-=4ReK3@^LFvNQI~(Pdvp+X@J@g#bd~m0wFc+sW3Xf5tyA3xKp;T3 zy14<o-`F}$ET-DQ;B;yNy?d>w%-4W!{IXZ)fWx@XX6;&(m_F%c6~X8hx=BN1&q}*( zoaNjWabE{oUPb!Bt$eyd#$5j9rItB-h*5JiNi(v^e|XKAj*8(k<5-2$&ZBR5fF|JA z9&m4fbzNQnAU}r8ab>fFV%J0z5awe#UZ|bz?Ur)U9bCIKWEzi2%A+5CLqh?}K4JHi z4vtM;+u<SJ)DEVF_yZnTw01M`(s#^BNx+c|MQ6ogb50Jjul0L;!#OmrYCs)iE)7(t z?%I~O!zVNt#Bf3#O2WXsGz!B}&s@MfyDeaoqqf=GELN3g$+DA`&&GKy(`Ya~A@6vK zn|WZ-+tB`DH^+SjI&K3KekF%-QIP%R{F)inWc~@cEO-=3Or<lm9g9}|`|ky#v{5*; zKA5d<ecC{<o9p<U4UUK$m|+q#@(>PsVz{Lfr;78W78gC;z*yTch~4YkLr&m-7%-xc ztw6Mh2<b07B|^BQBjvq{FXx?kyJ);`+G*=&9PMD`1uf<{+pNnnsIQx~kaB?*5<-7a zqY)GyF_w$>d>_iO<o;tRi5=dcnU&wcur@4T5Z=-$xFUEsp-yX${|jSF|HMDPq3?MS zw;p9zjR`yYJOfJZsK~C-S=JQ?nX{z_y@06JFIpheAo-rOG|5&Gxv)%95gpu@ESfi| z7Auc&hjVL;&81Pc#L`^d9gJb`wEtLVH8q|h{>*$Rd8(-Cr1_V8EO1f*^@wRoSozS) zy1UoC@pruAaC8Z_7~_w4Q6n*&B0AjOmMWa;s<dwKr_&w<X$Z*rmLmKUI3S>Iav&gu z|J5&|{=a@vR!~k-OjKEgPFCzcJ>#A1uL&7xTDn;{X<DkOU(-L87#5hf4{m?aj!I6- zPEt$K07IXK8mI0TYf-jhke2QjQw3v?qN5h0-#Fel0)Krq1f)#^AFsfd|K$I={`Xs9 z{JIr8M>BdeM}V=l3B8fE1--DHjSaxoSjNKEM9|U9#m2<eS=8Og#NOG$&X&%|8sOyg zpZ6&%KPd&uh?v{hRMVvQjUL}gY3)Mk3{XQXF{><3>n{Iuo`r3UZp;>GkT2YBNAh|b z^jTq-hJp(ebZh#Lk8hVBP%qXwv-@vbvoREX$TqRGTgEi$%_F9tZES@z8Bx}$#5eeG zk^UsLBH{bc2VBW)*EdS({yw=?qmevwi?BL6*=12k9zM5gJv1>y#ML4!)iiPzVaH9% zgSImetD@dam~e>{LvVh!phhzpW+iFvWpGT#CVE5TQ40n%F|p(sP5mXxna+Ev7PDwA zamaV4m*^~*xV+&p;W749xhb_X=$|LD;FHuB&JL5?*Y2-oIT(wYY2;73<^#46S~Gx| z^cez%V7x$81}UWqS13Gz80379Rj;6~WdiXWOSsdmzY39L;Hg3MH43o*y8ib<ko|2T z<o~B%-$Y4Q9z_t97c`{g0veSfFt63Osbpe2Osn@<=nrAVk_JfMGt&lMGw9leshc#5 z*hkn0u>NBBH`(av4|u;YPq%{R;IuYow<+GEsf@R?=@tT@!}?#>zIIn0CoyV!hq3mw zHj>OOjfJM3F{RG#6ujzo?y32m^tgSXf@v=J$ELdJ+=5j|=F-~hP$G&}tDZsZE?5rX ztGj`!S>)CFmdkccxM9eGIcGnS2AfK#gXwj%esuIBNJQP1WV~b~+D7PJTmWGTSDrR` zEAu4B8l>NPuhsk5a`rReSya2nfV<T&F{)-N{)9$`9a!^D!-03RDN<TPH!aW46TC4L z>1EK01+G!x8aBdTs3Io$u5!6n6KX%uv@DxAp3F@{4UYg4SWJtQ-W~0MDb|j-$lwVn znAm*Pl!?Ps&3wO=R115RWKb*JKoexo*)uhhHBncEDMSVa_PyA>k{Zm2(wMQ(5NM3# z)jkza|GoWEQo4^s*wE(gHz?Xsg4`}HUAcs42cM1-qq_=+=!Gk^y710j=66(cSWqUe zklbm8+zB_<cF$~mH3zum`PN7rn^cr1XvcjzxFO{ms_482AyMFYi+#o7!*vecrNhft z48z<2q#fIw=ce!MXuptfT4+M8FP&|QfB3H@2)dceSR<*e5@hq<#7<$5tC^!RO8Zi< zd_Wl!>syQv5A2rj!Vbw8;|$@C!vfNmNV!yJ<MblqN@23-5g1<aeoul%Um5K((_QY} ze%_@BuNzay69}2PhmC<;m}2=FevDzrp!V!u4u|#h@B=rfKt+v!U`0k7>IWDQ>{+2x zKjuFX`~~HKG~^6h5FntRpnnHt=D&rq0>IJ9#F0eM)Y-)GpRjiN7gkA8wvnG#K=q{q z9dBn8_~wm4J<3J_vl|9H{7q6u2A!cW{bp#r*-f{gOV^e=8S{nc1DxMHFwuM$;aVI^ zz6A*}m8N-&x8;aunp1w7_vtB*pa+OYBw=TMc6Q<xVqo{NJ3h9-a)s5XuYMqZ=Y{7{ z$O63J`)FM-y*mko#!-UBa!3~eYtX1hjRQY2jMxAx=q5uKNm#uaKIak>K=mbA-|Cf* zvyh8D4LRJImooUaSb7t*fVfih<97Gf@VE0|z>NcBwBQze);Rh!k3K_sfunToZY;f2 z^HmC4KjHRVg+eKYj;PRN^|E0>Gj_zagfRbrki68I^#~6-HaHg3BUW%<xsJq4AotN+ zH6twFV=)FlAbs*F6vGws^==x5Tl0AIbcP{&2yxB=)*u+bvK^L6$Vp}U2{9nj{bK~d zee7tC)@DR<dI`D%cA(%7M9Ui3a)^iG?m=oJO0E^``<|5il2sf1fZHvy=D@e0<I)<l zI!|d{`X3u}lz2(4Vn>+clM1<yhZZgPANro5CwhUb>xQEdPYt_g<2K+z!$>*$9nQ>; zf9Bei{?zY^-e{q_*|W#2rJG`2fy@{%6u0i_VEWTq$*(ZN37|8lFFFt)nCG({r!q#9 z5VK_kkS<W$zJN%xs9<lngf<utn=i|I;bCdr-Lr<EzK)tkE-pYh-fc0wqKz?&U8TTN zh_eAdl<>J3?zOH)OezMT{!YkCuSSn!<oaxO4?NS?VufjhPn>K#-Rhl$uUM(bq*jY? zi1xbMVthJ`E>d>(f3)~fozjg^@eheMF6<)I`oeJYx4*+M&%c9VArn(OM-wp%M<-`x z7sLP1&3^%Nld9Dhm@$3f2}87!quhI<BVn6Upp<cc;cU|)&2W%nk!Ak8tXK8aT!m*5 z^9zmeeS|PCG$hgM&Uh}0wp+#$jK3YCwOT&nx$??=a@_oQemQ~hS6nx6fB5r~bFSPp z`alXuTYys4S5dCK)KDGR@7`I-JV^ewQ_BGM^o>@nwd@3~fZl_3LYW-B?Ia>ui`ELg z&Qfe!7<FViITCBP{rA>m6ze=mZ<W0bN&bq-0D3>`Ia9$z|ARSw|IdMpooY4YiPN8K z4B(ts3p%<w%rbophph+BzYj>2i(Td=<hfIaF6Ll8+9!48Ti=xpXB{FgJbk;>tgEHX z0UQ_>URBtG+-?0E;E7Ld^dyZ;jjw0}XZ(}-QzC6+NN=40oDb2^v!L1g9xRvE#@IBR zO!b-2N7wVfLV;mhEaXQ9XAU+>=XVA6f&T4Z-@AX!leJ8obP^P^wP0aICND?~w&N<u ztispy>ykJ#54x3_@r7IDMdRNy4Hh;h*!u(Ol(#0bJdwEo$5437-UBjQ+j=Ic>Q2z` zJNDf0yO6@mr6y1#n3)s(W|$iE_i8r@Gd@!DWD<Q)gT}bxTg_YpJQ5s|m8}+B)KBN6 zYnlzh>qZ7J&~gAm1#~maIGJ<sH@F<m!Fuh_fvrMbcDJNJ5~Yg;LF}NFN}&Y&LL76S zv)~8W2?_rx`P;4LB-=JqsI{I~4U8DnSSIHWU2rHf%vWsA2-d=78An8z4q|lvgQ2iB zhUUI!H+|C+_qp(Tjzu5usOu}cEoivZK&XA==sh0cD|Eg7eERXx?KwHI=}A9S_rx8S zd)VLh_s!Juqi^!0xv7jH)UdSkEY~N|;QMWvs;HN`dMsdK=Dw2mtAHHcK8_+kS%a_V zGgeQoaMM>1sls^gxL9LLG_Nh<XXk<>U!pTGty!TbhzQnu)I*S^54U6Yu%ZeCg`R>Q zhBv$n5j<?~h)Y%y=zErI?{tl!(JWSDXxco7X8WI-6K;9Z-h&~kIv?$!6<k(g(xee? z53>0v%O_j{QYWG!R9W?5_b&67KB$t}&e2LdMvd(PxN6Ir!H4>PNlerpBL>Zvyy!yw z-SOo8caEpDt(}|gKPBd$qND5#a5nju^O>V&;f890?yEOfkSG^HQVmEbM3Ugzu+UtH zC(INPDdraBN?P%kE;*Ae%Wto&sgw(crfZ#Qy(<4nk;S|hD3j{IQRI6Yq|f^basLY; z-HB&Je%Gg}Jt@={_C{L$!RM;$$|<j7k-g{75e!h)4SlFvEZ*AkqrJI;EWu$Zx+OwM zm{5Yk>iD6vu#3w?v?*;&()uB|I-XqEKqZPS!reW9JkLewLb!70T7n`i!gNtb1%vN- zySZj{8-1>6E%H&=V}LM#xmt`J3XQoaD|@XygXjdZ1+P77-=;=eYpoEQ01B@L*a(uW zrZeZz?HJsw_4g0vhUgkg@VF8<-X$B8pOqCuWAl28uB|@r`19DTUQQsb^pfqB6QtiT z*`_UZ`fT}vtUY#%sq2{rchyfu*pCg;uec2$-$N_xgjZcoumE5vSI{+s@iLWoz^Mf; zuI8kDP{!XY6OP~q5}%1&L}CtfH^N<3o4L@J@zg1-mt{9L`s^z$Vgb|mr{@WiwAqKg zp#t-lhrU>F8o0s1q_9y`gQNf~Vb!F%70f}$>i7o4ho<sjDlFD=G`r<7$U?bJN+x5S z@0&tQ=-XO1uDq(HCa$X)-l<u1!s<!W`30F78UcZaZKc8)G0af1Dsh%OOWh5)q+Q+n zySBnE+3;9^#)U#Gq);&Cu=mtjNpsS~S0yjE@m4{Kq525G&cO_+b-_B$LeXWt_@XTq z`)(;=^RDS@oh5dPjKyGAP?-Dbh507E5zZ=D2_C*6s^HXiA)B3f=65_M+rC&rMIUP6 zi4@u>$`uciNf=xgJ>&!gSt0g;M>*x4-`U)ysFW&Vs^Vk6m%?iuWU+o&m(2Jm26<Ea z?or_^bK_`R)hBTfrBqA3Y^o7$K~Nzo)sh-vT%yWcc1I5wF1nkvk%!X_Vl_MK1IHC= zt}Dt+sOmg0sH-?}kqNB|M_}ZXui7H;?;?xCCSIPSHh8@h^K8WU5X(!3W|>Y(3%TL; zA7T)BP{WS!&xmxNw%J=$MPfn(9*^*TV;$JwRy8Zl*yUZi8jWYF>==j~&S|Xinsb%c z2?B+kpet*muEW7@AzjBA^wAJBY8i|#C{WtO_or&Nj2{=6JTTX05}|H>N2B|Wf!*3_ z7hW*j6p3TvpghEc6-wufFiY!%-GvOx*bZrhZu+7?iSrZL5q9}igiF^*R3%DE4aCHZ zqu>xS8LkW+Auv%z-<1Xs92u23R$nk@Pk}MU5!gT|c7vGlEA%G^2th&Q*zfg%-D^=f z&J_}jskj|Q;73NP4<UD^T*M!yxMr=U!@&!rJfydk7CE7PGb<{)^=nM9Le#FQ=GkV~ z)_A$YPAn35??iNa@`g-wBX><4k*Y%pXPU2Thoqr+5uH1yEYM|VtBPW6lXaetokD0u z9qVek6Q&wk)tFbQ8(^HGf3Wp16gKmr>G;#G(HRBx?F`9AIRboK+;OfHaLJ(P>IP0w zyTbTkx_THEOs%Q&aPrxbZrJlio+hCC_HK<4%f3ZoSAyG7Dn`=X=&h@m*|UYO-4Hq0 z-Bq&+Ie!S##4A6OGoC~>ZW`Y5J)*ouaFl_e9GA*VSL!O_@xGiBw!AF}1{tB)z(w%c zS1Hmrb9OC8>0a_$BzeiN?rkPLc9%&;1CZW*4}CDDNr2gcl_3z+WC15&H1Zc2{o~i) z)LLW=WQ{?ricmC`G1GfJ0Yp4Dy~Ba;j6ZV4r{8xRs`13{dD!xXmr^Aga|C=iSmor% z8hi|pTXH)5Yf&v~exp3o+sY4B^^b*eYkkCYl*T{*=-0HniSA_1F53eCb{x~1k3*`W zr~};p1A`k{1DV9=UPnLDgz{aJH=-LQo<5%+Em!DNN252xwIf*wF_zS^!(XSm(9eoj z=*dXG&n0>)_)N5<wxn0{TP0tnD=JAzVUcIUoR85Xt>oc6v!>-bd(2ragD8O=M|wGW z!xJQS<)u70m&6OmrF0WSsr@I%T*c#Qo#Ha4d3COcX+9}hM5!7JIGF>7<~C(Ear^Sn zm^ZFkV6~Ula6+8S?oOROOA6$C&q&dp`>oR-2Ym3(HT@O7Sd5c~+kjrmM)YmgPH*tL zX+znN>`tv;5eOfX?h{AuX^LK~V#gPCu=)Tigtq9&?7Xh$qN|%A$?V*v=&-2F$zTUv z`C#WyIrChS5|Kgm_GeudCFf;)!WH7FI60j^0o#65o6`w*S7R@)88n$1nrgU(oU0M9 zx+EuMkC>(4j1;m6N<sS-ys^qbJhGY7%0ZoC7dK=j7bGdau`J`{>oGqEkpJYJ?vc|B zOlwT3<tNmX!mXZdsEW2s2`|?DC8;N?2tT*Lfq)F*|4vf>t&UgL!pX_P*6g36`ZXQ; z9~Cv}ANFnJGp(;ZhS(@FT;3e)0)Kp;h^x;$*xZn*k0U6-&Fw<BqOnDKEdld8!Qk{Z zjI1+R_ciEqL3CLOv$+J~YVpzIy`S&V{koIi$Lj}ZFEMN=!rL1?_EjSryIV+OBiiJ- zIqT$oSMA>I=uOGaODdrsp-!K$Ac32^c{+FhI-HkYd5v=`PGsg%6I`4d9Jy)uW0y%) zm&j^9WBAp*P8#kGJUhB!L?a%h$hJgQrx!6KCB_TRo%9{t0J7KW8!o1B!NC)VGLM5! zpZy5Jc{`r{1e(jd%jsG7k%I+m#C<kI0i<ajCqQC!(pKlSsMl7M2N^mP%W`BGKb?hm zBK`pddcg5+WhE#$46+K<Z!1CW-hZdo7hAw13ZUVqwW*}&ujL=eh{m~phuOy=JiBMN z7FaCUn6boJ!M=6PtLN6%cveGkd12|1B{)kEYGTx#IiMN&re0`}NP-_{E-#FxOo3*P zkAXSt{et292KfgGN`AR|C`p{MRpxF-I?+`ZY1Vsv>GS*BPA65ZVW~fLYw0dA-H_}O zrkGFL&P1PG9p2(%Qi<evvBkNEkQkM%A>EWm6x;U-U&I#;Em$nx-_I^wtgw3xUPVVu zqSuKnx&dIT-XT+T10p;yjo1Y)z(x1fb8Dzfn8e yu?e%!_ptzGB|8GrCfu%p?(_ zQccdaaVK$5bz;*rnyK{_SQYM>;aES6Qs^lj9lEs6_J+%nIiuQC*fN;z8md>r_~Mfl zU%p5Dt_YT>gQqfr@`cR!$NWr~+`CZb%dn;WtzrAOI>P_JtsB76<bUr7Lsb65vEd}g z5JhMCmn#UeH#6Cew?bxogM)$x5ed{E)%2nWY5rb@Clvh$(JzQ#!CsQ(2I4QnhDDJ^ zYL%2bf8?`y)Ro=x{(dw<4^)(H^z7~3nfYFh-r7yBBb=l3V8dE-Dr&a%qs<OYcajo2 z(4Nw|k5_OQ@6zHmcIK%waj!yoZT(S1YlEFN?8-_lp9nf>PYe*<%H(y>qx-`Kq!X_; z<{RpAqYhE=L1r*M<cT6p|4(5fVa-WIh|@AphR|cJ1`?N>)gNF3B8r(<%8mo*SR2hu zccLRZwGARt)H<F*kMvg%oJV~29ud_q>lo1euqTyM>^!HK*!Q2P;4UYry<i)yWXzKa zM^_qppY~vnIrhL_!;Z9msXMZTTwR{e`yH5t=HdD1Pni7?LqOpLoX}u5n5RfkGBvQ1 z@cdMeR4T6rp^S~>sje@;(<|$&%vQekbn|0Ruu_Io(w4#%p6ld2Yp7tlA`Y$cciThP zKzNGIMPXX%&Ud0uQh!uQZz|FB`4KGD?3!ND?wQt6!n*f4EmCoJUh&b?;B{|lxs#F- z31~HQ`SF4x$&v00@(P+j1pAaj5!s`)b2RDBp*PB=2IB>oBF!*6vwr7Dp%zpAx*dPr zb@Zjq^XjN?O4QcZ*O+8>)|HlrR>oD*?WQl5ri3R#2?*W6iJ>>kH%KnnME&TT<gNU{ zn$Veg044#l=Z-&wsmEZhnw7IwT7Cd}hiZ%ke)-GzAR-Dt6)8Cb6>@Z<Y-SEE^OC5H z=$M0HjdWR5p?n;s9OTXrEa1eGt}G;Eu)ifSop!$z#6V<>zrHS$Q%LC?n|e>V+D+8D zYc4)QddFz7I8#}y#Wj6>4P%34dZH<AWj}HgE@5&D9Ra@o(Km_Gm}5Zb61p%9mDz1% zya$Vd!_U~pDN*Y5%lo}-K~}4&F)rTjJ7uGyV@~kB-XNrIGRiB=UrNxJtX;JHb(EyQ z{!R%v{vC7m|L3bx6lCRb7!mP~Is!r!q&OXpE5nKnH3@l({o}PrL`o>~OUDb?uP%-E zwjXM(?Sg~1!|wI(RVu<h{6ESg9k500(D<HXwz52OGq(JEKS2CJR}8N&E-#%vhhaRN zL#Q6%yUcel+!a#~g&e7w4$3s62d$Dv;SxCxhT}>xbu)-rH+O=igSho_pDCw(c6b=P zKk4ATlB?bj9+HHlh<_!&z0rx13K3ZrAR8W)!@Y}o`?a*JJsD+twZIv`W)@Y?Amu_u zz``@-e2X}27$i(2=9rvIu5uTUOVhzwu%mNazS|lZb&PT;XE2|B&W1>=B58#*!~D&) zfVmJGg8UdP*fx(>Cj^?yS^zH#o-$Q-*$SnK(ZVFkw+er=>N^7!)FtP3y~Xxnu^nzY zikgB>Nj0%;WOltWIob|}%lo?_C7<``a5hEkx&1ku$|)i>Rh6@3h*`slY=9U}(Ql_< zaNG*J8vb&@zpdhAvv`?{=zDedJ23TD&Zg__snRAH4eh~^oawdYi6A3w8<<tS1{)`* zH!u#2_lf&B)x2)tE$?4|aMAYUFZ{|Se7->Ozh@Kw)<E~4fKYaJ{OS+>#bdktM^GVb zrG08?0bG?|NG+w^&JvD*7LAbjED{_Zkc`3H!My>0u5Q}m!+6VokMLXxl`Mkd=g&Xx z-a>m*#G3SLlhbKB!)tnzfWOBV;u;ftU}S!NdD5+YtOjLg?X}dl>7m^gOpihrf1;PY zvll&>dIuUGs{Q<Ww4SS<E23Sm*si$^C!!snD|AFym<+q$`*o0wokE?J{^g?f3>nd- zwIR3oIrct8Va^Tm0t#(bJD7c$Z7DO9*7NnRZorrSm`b`cxz>OI<bVZt$VQ!oMxCu0 zbb7D5OIXV5Ynn@Y6)HLT=1`a=nh7{ee{vr<=$>C;jSE3DO8`hX955ui`s%||YQtt2 z5DNA&pG-V+4oI2s*x^>-$6J?p=I>C|9wZF8z;VjR??Icg?1w2v5Me+FgAeGGa8(3S z4vg*$>zC-WIVZtJ7}o9{D-7d>zCe|z#<9>CFve-OPAYsneTb^JH!Enaza#j}^mXy1 z+ULn^10<XTm*l1Jg2Z;UvGEN!6Wq%I@OP4p{k`RNRKlKFWPt_of11^Gr%_Mg*mVP3 zm?)&3I719~aYcs)TY&q^$zmQ=xoC++VJH@~YG6>+rWLF6j2>Ya@@Kq?26>AqK{A_| zQKb*~F1>sE*=d?A?W7N2j?L09_7n+H<SF8|SM#pTc9|9|rf1w*m4Y0Vdj643qA#D| z!hJzb_-}IrrhkWr{zk_YC%(c-)UJl6Ma!mcbvj&~#yN-UhH?ZQ3TPq4hTVQ$(?eJ6 zNfJ_K+VJDBXN=l!7{2}lq?-$`fq|e&PEONfZDU<_SM+s2_3$vT_yqV<R&KG=K{zS} zKQF$?mYsg%vV|E_E=a*SL!`7*AeN6GMVDXC59yPgi$F2!7&8e}EyHVLwCm{i%<pN! zdc`SbZK}JQj7?6K&|261iHrsnVjdhxu_l_NKs&yy#;#^%8?Jlg`wcTlNZ3urUtEYd zsFE!K0}Eg39)z+J6mLW)#Kn<ok4*6AAE=n*vh*;TpgGnnM|npykFpO|a0`4#SjP^b z2<JG#Qk^#3FeFS`0eooK9|wEmCcvRKI*~6mamFTd^UW9Eg4!J4N9qz*C$3a#F;Sad zi#o9LaqNG5TsiT<`SDtY^`)zkYx$(C5;&K9#(Zj}HolT_st~#C`VS8q%#q1)HN+hT zz9IjVUdZNIp@;b88oR`~DvQL_zmsBy>Gi{VY;MoTGr_)G9)ot$p!-UY5zZ2Xtbm=t z@dpPSGw<TLTZo~Zyx(+AKWvR~{L4S^5I;5+QT9bcQ-4cC{QnLfRBf&Pov~kv@`W6V zA|h{EGx|7msvR1t`a-jF$JZ>gH=QtIcEulQNI>S-#ifbnO5EWkI;$A|pxJd885oM+ zGZ0_0gDvG8q2xebj+fbCHYfAXuZStH2j~|d^sBAzo46(K8n59+T6rzBwK)^rfPT+B zyIFw)9YC-V^rhtK`!3jrhmW-sTmM+tPH+;nwjL#-SjQPUZ53L@A>y*rt(#M(qsiB2 zx6B)dI}6Wlsw%bJ8h|(lhkJVogQZA&n<jl%@&gd%^X|lsDQwDHEiKLCz}r`kC^h0t z(!vYS%C)Ku?w$ti5R##9jSkNC#5)Juc{8XfEhczdGQy8yNrZL6+d0~%V=N|iF{V)E zLT(gH!$j8Mf(1>{?Vgs6gNSXzuZpEyu*xySy8ro07QZ7Vk1!3tJphN_5V7qOiyK8p z#@jcDD8nmtYi1^l8ml;AF<#IPK?!pqf9D4moYk>d99Im}Jtwj6c#+A;f)CQ*f-hZ< z=p_T86jog%!p)D&5g9taSwYi&e<jP@@Q_fbXtVO&n9{e#)jg+D#~q=hoZ<9PIa)>P z#JuEK%+NULWus;0w32-SYFku#i}d~+{Pkho&^{;RxzP&0!RCm3-9K6`>KZpnzS6?L z^H^V*s!8<>x8bomvD%rh>Zp3>Db%kyin;qtl+jAv8Oo~1g~mqGAC&Qi_wy|xEt2iz zWAJEfTV%cl2Cs<1L&DLRVVH05EDq`pH7Oh7sR<WSzBWU(MxAIA&4v~INVdLKA><BK zwCgTxJU0mM{;1UV<^ZRk0SQNNN(;SRZsH7^EDWVUu%^mFfvW{m5jOQuQWSy`f586I zTj}Z4e5WsvkNmBd`TJdfe=^>`NNkL%wi}8n>IXcO40hp+J+sC!W?!krJf!GJNE8uj zg-y~Ns-<~D?yqbzVRB}G>0A^f0!^N7l=$m0OdZuqA<e9rzV|ixGyk9uS=Vov2_ECA z^Sd0M$B)O&tv@%@UmTb%ngcl58ED9TyFp$y4JjFU+g+9EWUl?am<e#4uCGy9Tmt)z z2Y|kWUahugFHsF<J6o!<?X(Ncsy&Wg9<QLPD}g-`PWGHWDY5P6;<Y+5J1vz2Z|PSy zBN?Q^NkxnWq>OQq<EC8_d&#T2smn`YINd-HF@)Op)pBRHnx+Q|Hsv_BpWAPsT1>Lc zX?AEGr1Ht+inZ-Qiwnl@Z0qukd__a!C*CKuGdy5#nD7VUBM^6OCpxCa2A(X;e0&V4 zM&WR8+wErQ7UIc6LY~Q9x%Sn*Tn>>P`^t&idaOEnOd(Ufw#>NoR^1QdhJ8s`h^|R_ zXX`c5*O~Xdvh%q;7L!_!ohf$NfEBmCde|#uVZvEo>OfEq%+Ns7&_f$OR9xsihRpBb z+cjk8LyDm@U{YN>+r46?nn{7Gh(;WhFw6GAxtcKD+YWV?uge>;+q#Xx4!GpRkVZYu zzsF}1)7$?%s9g9CH=Zs+B%M_)+~*j3L0&Q9u7!|+T`^O{xE6qvAP?XWv9_MrZKdo& z%IyU)$Q95AB4!#hT!_dA>4e@zjOBD*Y=XjtMm)V|+IXzjuM;(l+8aA5#Kaz_$rR6! zj>#&^DidYD$nUY(D$mH`9eb|dtV0b{S>H6FBfq>t5`;OxA4Nn{J(+XihF(stSch<f zIn>e7$es&~N$epi&PDM_N`As;*9D^L==2Q7Z2zD+CiU(|+-kL*VG+&9!Yb3LgPy?A zm<g7T4Wx!m(zMlVE_2jX$1$$5DcfL6>7Z&^qRG_JIxK7-FBzZI3Q<;{`DIxtc48k> zc|0dmX;Z=W$+)qE)~`yn6MdoJ4co;%!`ddy+FV538Y)j(vg}5*k(WK)KWZ3WaOG!8 z!syGn=s{H$odtpqFrT#JGM*utN7B((abXnpDM6w56nhw}OY}0TiTG1#f*VFZr+^-g zbP10`$LPq_;PvrA1XXlyx2uM^mrjTzX}w{yuLo-cOClE8MMk47T25G8M!9Z5ypOSV zAJUBGEg5L2fY)ZGJb^E34R2z<C?_X1)4xsl9%Z|w&L9k!F(V>J?}Vf>{~gB!8=5Z) z9y$>5c)=;o0HeHHSuE4U)#vG&KF|I%-cF6f$~pdYJWk_dD}iOA>iA$O$+4%@>JU08 zS`ep)$XLPJ+n0_i@PkF#ri6T8?ZeAot$6JIYHm&P6EB=BiaNY|aA$W0I+nz*zkz_z zkEru!tj!QUffq%)8y0y`T&`fuus-1p>=^hnBiBqD^hXrPs`PY9tU3m0np~rISY09> z`P3s=-kt_cYcxWd{de@}TwSqg<T-v~${38)1dqT{JCO5}Gk$$yZP*X!5)RaGFqqkZ zeHhqUgXb37$91~LS-3Zi29CKKki0sBTh7unqEK$%FG?oo$Sp>*xVhp;E9zCsnXo6z z?f&Sv^U7n4`xr=mXle94HzOdN!2kB~4=%)u&N!+2;z6UYKUDqi-s6AZ!haB;@&B`? z_TRX0%@suz^TRdCb?!vNJYPY8L_}&07uySH9%W^Tc&1pia6y1q#?*Drf}GjGbPjBS zbOPcUY#*$3sL2x4v_i*Y=N7E<UbOmi3K%)5<dOJui+{^+b*shA_w8&X4_Icv*!}kT zW@BG{C%f{(K^kE?tjU`Led*kAj6wB_3f*UyIEV0T9TyMo4`NS;oA7Ec+71eFa;K|G zCyaKKi1bvX9fTLQ+uAgF*@ZR8fB%|JlT8A-jK$7FMyxW>$mR}J%|GUI(>WEr+28+V z%v5{#e!UF*6~G&%;l*q*$V?&r$Pp^sE^i-0$+RH3ERUUdQ0>rAq2(2QAbG}$y{de( z>{qD~GGuO<V3ijl7+~xmS#nUvH{qF0*%7G(r|}BSXsu}HwrFbXWzcYJouIY*34axA z(n@XsPrv%6;|GSbkH9Og>k559Y@%$?N^1ApVL_a704>8OD%8Y%8B;FCt%AoPu8*D1 zLB5X>b}Syz81pn;xnB}%0FnwazlWfUV<Vu@5P52pgIa+J{M)H4nAC<>)Z-~rZg6~b z6!9J$EcE&sEbzcy?CI~=boWA&eeIa%z(7SE^qgVLz??1Vbc1*aRvc%Mri)AJaAG!p z$X!_9Ds;Zz)f+;%s&d<S0a>RcJt2==P{^j3bf0M=nJd&xwUGlUFn?H=2W(*2I2Gdu zv!gYCwM10aeus)`RIZSrCK=&oKaO_Ry~D1B5!y0R=%!i2*KfXGYX&gNv_u+n9wiR5 z*e$Zjju&ODRW3phN925%S(jL+bCHv6rZtc?!*`1<n2%>TyYXT6%Ju=|X;6D@lq$8T zW{Y|e39ioPez(pBH%k)HzFITXHvnD6hw^lIoUMA;qAJ^CU?top1fo@s7xT13Fvn1H z6JWa-6+FJF#x>~+A;D~;VDs2<i>6>^oH0EI`IYT2iagy23?nyJ==i{g4%HrAf1-*v zK1)~@&(KkwR7TL}L(A@C_S0G;-GMDy=MJn2$FP5s<%wC)4jC5PXoxrQBFZ_k0P<n- z??iM<JF!BTjD>{{s@<jPT1+pTPdk3<izB+}jAtjokIz)aPR$L&4%}45Et}?jz0w{( zC4G}+Nu0D*w=ay`v91hMo+V&V8q(a!`~K-2<yR0H)sK+mcY?TAaSS8F<Q+!pSc;`* z*c@5)+ZpT%-!K3O=Z0(hI8LH7KqK>sz+gX`-!=T8rcB(=7vW}^K6oLWMmp(rwDh}b zwaGGd>yEy6fHv%jM$yJXo5oMAQ>c9j`**}F?MCry;T@47@r?&sKHgVe$MCqk#Z_3S z1GZI~nOEN*P~+UaFGnj{{Jo@16`(qVNtbU>O0Hf57-P>x8Jikp=`s8xWs^dAJ9lCQ z)GFm+=OV%AMVqVATtN@|vp61VVAHRn87}%PC^RAzJ%JngmZTasWBAWsoAqBU+8L8u z4A&Pe?fmTm0?mK-BL9t+{y7o(7jm+RpOhL9Kn<D3v{}Wpv2i&ghEZe;t&DmOA_QYc zM+NIUU}=*bkxOJsLKV3e^oGG8rufTpa8R~7Iki1y+fC(UT;;{l19@qfxO@0^!xMA? z#|<YBZ6;vAb>Y#E&qu^}B6=K_dB}*VlSEiC9fn)+V=J;OnN)Ta5v66ic1rG+dGAJ1 z1%Zb_+!$=tQ~lxQrzv3x#CPb?CekEkA}0MYSgx$Jdd}q8+R=ma$|&1a#)TQ=l$1tQ z=tL9&_^vJ)Pk}EDO-va`UCT1m#Uty1{v^A3P~83_#v^ozH}6*9mIjIr;t3Uv%@VeW zGL6(CwCUp)Jq%G0bIG%?{_*Y#5IHf*5M@wPo6A{$Um++Co$wLC=J1aoG93&T7Ho}P z=mGEPP7Gb<mBTnJH7dKM2CB)0*o-AW2E4i5R+rHU%4A2BTVwOqj4zmJqsb|5^*{DT zv^HFARK6@^_1|vU{>voG!uD$k(H3A$Z))+i{Hy?QHdk>3xSBXR0j!11O^mEe9RH<y zF3MI;^J1vHI9U>mw!pvzv?Ua~2_l2Yh~_!s1qS`|0~0)<BWX>YsbHSz8!mG)WiJE| z2<APmuYD%tKwB@0u<C~CKyaC}XX{?mylzkDSuLMkAoj?zp*zFF7q515SrGD~s}ATn z`Ded41yk>f($6TQtt6L_f~ApQYQKSb=`053LgrQq7G@98#igV>y#i==-nEjQ!XNu9 z<h*hnP2Pol+z>~;mE+gtj4IDDNQJ~JVk5Ux6&LCSFL!y=>79kE9=V}J7tD==Ga+IW zX)r7>VZ9dY=V&}DR))xUoV!u(Z|%3ciQi_2jl}3=$Agc<a_3#EUXJj<z2jVv6VHGT zV^v1FiRwA!kPmt}m$qdr&9#-6{QeZqtM3|tRl$sws3Gy`no`Kj@X-)O(^sv>(`RPb z8kEBpvY>1FGQ9W$n>Cq=DIpski};nE)`p3IUw1Oz0|wxll^)4dq3;CCY@RyJgFgc# zKouFh!`?Xuo{IMz^xi-h=StCis_M7y<P{h0$_I#EukRYag9%BMRXh|%Xl7C<>q$u) z?XHvw*HP0VgR+KR6wI)jEMX|ssqYvSf*_3W8zVTQzD?3>H!#>InzpSO)@SC8q*ii- z%%h}_#0{4JG;Jm`4zg};BPTGkYamx$Xo#O~lBirRY)q=5M45n{GCfV<Kqrcu9<z@R zSE>7h9qwyu1NxOMoP4)jjZMxmT|IQQh0U7C$EbnMN<3)Kk?fFHYq$d|ICu>KbY_hO zTZM+uKHe(cIZfEqyzyYSUBZa8;Fcut-GN!HSA9ius`lt<SmSV9vasBl&hE7ciOunD z?%e1Hl-5B3e+<+8CD{j5U*D3h89nV<zn^0g+t=uRKgZiGu)3h;vu#^y`HqWe_=jGm zW2p}*n<!QH%pQ2EV`&z|LD#BOpj0QS9R5#$q}3&-+@GL4F^wO-bcSo|J^I_{LATPF z2$`fUCOO=XxYVD!<7Yz4te$d-_>NebF46ZX_BbZNU}}ZOm{M2&nAN<H$fJIKS=j8q zwXlN!l^_4>L9@0qvih15(|`S~z}m&h!u4x~(%MAO$jHRWNfuxWF#B)E&g3ghSQ9|> z(MFaLQj)NE0lowyjvg8z0#m6FIuKE9lDO~Glg}nSb7`~^&#(Lw{}GVOS>U)m8bF}x zVjbXljBm<v)#bs=9p`s>34Cs-yM6TVusr+3kYFjr28STT3g056y3cH5Tmge~ASxBj z%|yb>$eF;WgrcOZf569sDZOVwoo%8>XO>XQOX1OyN9I-SQgrm;U;+#3OI(zrWyow3 zk==|{<m8xZ#>lt2xrQ%FIXOTejR>;wv(Pb8u8}BUpx?yd(Abh<shPyABw|Ens8m6@ zIg($GO4)<g4x5icbki?U&2%56@tYd`zRs}Nk6R~4!AjVAihB3r8oDhQ8f)v^r}|(y z4B&Q<ARRqYXKQGAeJa_KHe`)04jUO~B=%q#SUlU@pU?apz0v{Al@s`Cvzo)u;2>6? zsoO3VYWkeLnF43&@*#MQ9-i-d0t*xN-UEyNKeyNMHw|A(k(_6QKO=nKMCxD(W(Yop zsRQ)QeL4X3Lxp^L%wzi2-WVSsf61dqliPUM7srDB?Wm6Lzn0&{*}|IsKQW;02(Y&| zaTKv|`U(pSzuvR6Rduu$wzK_W-Y-7>7s?G$)U}&uK;<>vU}^^ns@Z!p+9?St1s)dG zK%y6xkPyyS1$~&6v{kl?Md6gwM|>mt6Upm>oa8RLD^8T{0?HC!Z>;(Bob7el(DV6x zi`I)$&E&ngwFS@bi4^xFLAn`=fzTC;aimE^!cMI2n@Vo%Ae-ne`RF((&5y6xsjjAZ zVguVoQ?Z9uk$2ON;ersE%PU*xGO@T*;j1BO5#TuZKEf(mB7|g7pcEA=nYJ{s3vlbg zd4-DUlD{*6o%Gc^N!Nptgay>j6E5;3psI+C3Q!1ZIbeCubW%w4pq9)MSDyB{HLm|k zxv-{$$A*pS@csolri$Ge<4VZ}e~78JOL-EVyrbxKra^d{?|NnPp86!q>t<&IP07?Z z^>~IK^k#OEKgRH+LjllZXk7iA>2cfH6+(e&9ku5poo~6y{GC5>(bRK7hwjiurqAiZ zg*DmtgY}v83IjE&AbiWgMyFbaRUPZ{lYiz$U^&Zt2YjG<%m((&_JUbZcfJ22(>bi5 z!J?<7AySj0JZ&<-qXX;mcV!f~>G=sB0KnjWca4}vrtunD^1TrpfeS^4dvFr!65knK zZh`d;*VOkPs4*-9kL>$GP0`<?hW@{z#_gXtp%=2VbN+$~z+M($Vf(dl@)t-*82<$( zHi{FrD1wO9L~*Rc0{A2WU%f?ar(T9V1JpQ?M0Q|&{UES|#Z~k2-mj@z)8Rw^(XeYc zomT(B0EF!##4dQq_*NN<%Bo5)&+gCXSGZo`b>(M!j~B;#x?Ba<KDM~HJ!|Zzy=p2e z8;av`GLw{_*RgO(W|UK-<iDeT!t_x1c=M3%wGk|fDk<e0lLe8-5ga6apKYJD`*a3G zBl?Ps)hDb7X`7bW5S=IHr0Mm?fr|$zCf+gmZUrit$5n+)JZG>~&s6CopvO86oM?-? zOw#dIRc;6A<R&%m3DDJhF+|tb*0Yw8mV{a-bf^E~gh66MdsMHkog<r9`fVIVE+h@O zi)iM`rmA-Fs^c=>6T?B`Qp%^<<Dyu<%Kg0H=lq;E!p&UHzSpD1)q%^v)Y8yQkp>U5 z19x(ywSH$_N+Io!6;e?`tWaM$`=D<O;$E>b!gzx|lQ${DG!zb1Zl&|{kX0y6xvO1o z220r<-oaS^^R2pEyY;=Qllqpmue|5yI~D|iI!IGt@iod{Opz@*ml^w2bNs)p`M(Io z|E;;m*Xpjd9l)4G#KaWfV(t8YUn@A;nK^#xgv=LtnArX|vWQVuw3}B${h+frU2>9^ z!l6)!Uo4`5k`<<;E(ido7M6lKTgWezNLq>U*=uz<KVOwgK<qq^3FEy1LAV}ep3|Zt z>&s=cc$1%>VrAeOoUtA|T6gO4>UNqsdK=NF*8|~*sl&wI=x9-EGiq*aqV!(VVXA57 zw9*o6Ir8Lj1npUXvlevtn(_+^X5rzdR>#(}4YcB9O50q97%rW2me5_L=%ffYPUSRc z!vv?Kv>dH994Qi>U(a<0KF6NH5b16enCp+mw^Hb3Xs1^tThFpz!3QuN#}KBbww`(h z7GO)1olDqy6?T$()R7y%NYx*B0k_2IBiZ14&8|JPFxeMF{vSTxF-Vi3+ZOI=Thq2} zyQgjYY1_7^ZQHh{?P))4+qUiQJLi1&{yE>h?~jU%tjdV0h|FENbM3X(KnJdPKc?~k zh=^Ixv*+smUll!DTWH!jrV*wSh*(mx0o6}1@JExzF(#9FXgmTXVoU+>kDe68N)dkQ zH#_98Zv$}lQwjKL@yBd;U(UD0UCl322=pav<=6g>03{O_3oKTq;9bLFX1ia*lw;#K zOiYDcBJf)82->83N_Y(J7Kr_3lE)hAu;)Q(nUVydv+l+nQ$?|%MWTy`t>{hav<vVD zHx;qQ>FSQloHwiIkGK9YZ79^9?AZo0ZyQlVR#}lF%dn5n%xYksXf8gnBm=wO7g_^! zauQ-bH1Dc@3ItZ-9D_*pH}p!IG7j8A_o<ZOCWxl^<k=*NA9oUpW$0D`yCb}VfC~vb z4IkfiRDM@RHlIGG_SRrrd~6$XYP~2Y^<fekveOOZRCv69S{4_se`>94#~>$LR|TFq zZ-b00*nuw|-5C2lJDCw&8p5N~Z1J&TrcyErds&!l3$eSz%`(*izc;-?HAFD9AHb-| z>)id`QCrzRws^9(#&=pIx9OEf2rmlob8sK&xPCWS+nD~qzU|qG6KwA{zbikcfQrdH z<yJStD<g^`?^d44p$8FFXwD2dL810^xg@~^x$C_H#3NSLs8fBVu~K)3BMKCOp^;|& zKPz+s!|fXFr%*`Dg*#A{!QB-jnah3y4$Pe0L2%RM)706&eqyFTNAO2gMd<bcjBp>+ zQg>O<`K4L8rN7`GJB0*3<3`z({lWe#K!4AZLsI{%z#ja^OpfjU{!{)x0ZH~RB0W5X zTwN^w=|nA!4PEU2=LR05x~}|B&ZP?#pNgDMwD*ajI6oJqv!L81gu=KpqH22avXf0w zX3HjbCI!n9>l046)5rr5&v5ja!xkKK42zmqHzPx$9Nn_MZk`gLeSLgC=LFf;H1O#B zn=8|^1iRrujHfbgA+8i<9jaXc;CQBAmQvMGQPhFec2H1knCK2x!T`e6soyrqCamX% zTQ4dX_E*8so)E*TB$*io{$c6X)~{aWfaqdTh=xEeGvOAN9H&-t5tEE-qso<+C!2>+ zskX51H-H}#X{A75wqFe-J{?o8Bx|>fTBtl&tc<VVc3-U5wTq>bdR|<Uon(X?ZiT<< zWC=zLEjacGDZ|?>132Ztqu5X0i-pisB-z8n71%q%>EF}yy5?z=Ve`}hVh{Drv1YWL zW=%ug_&chF11gDv3D6B)Tz5g<uwqk#dj|RK7gNl@*lm*xHRBk*7MnT4(@7VIDfO0u zB?1X+)GR^0j1A{Q#WUmQX%LN=W?aGzO$5=2@yxjXBzxbGO*{DYkV!aJ!$~-FNzvt; z?r)HU;0!4T-%vWzAiHJ?*-ivIq!#dErMvhpJJ^QyZ5n0qmMn+}I>54H0mDHNj<FD1 z&CIP+ZDDy<;b2`JW=0_p9c4p<zwE30JFgdhO2HQiMRBb%Y9ZJ>uKZ+)CKFk4Z|$RD zfRuKLW`1B>B?*RUfVd0+u8h3r-{@fZ{k)c!93t1b0+Q9vOaRnEn1*IL>5Z4E4dZ!7 ztp4GP-^1d>8~LMeb}bW!(aAnB1tM_*la=Xx)q(I0Y@__Zd$!KYb8T2VBRw%e$iSdZ zkwdMwd}eV9q*;YvrBFTv1>1+}{H!JK2M*C|TNe$ZSA>UHKk);wz$(F$rXVc|sI^lD zV^?_J!3cLM;GJuBMbftbaRUs$;F}HDEDtIeHQ)^EJJ1F9FKJTGH<(Jj`phE6OuvE) zqK^K`;3S{Y#1M@8yRQwH`?kHMq4tHX#rJ>5lY3DM#o@or4&^_xtBC(|JpGTfrbGkA z2Tu+AyT^pHannww!4^!$5?@5v`LYy~T`qs7SYt$JgrY(w%C+IWA;ZkwEF)u5sDvOK zGk;G>Mh&elvXDcV69J_h02l&O;!{$({fng9Rlc3ID#tmB^FIG^w{HLUpF+iB`|<Dd z$~}?*yaE3d3m&(}pR(IuL%&h+j{wz$6(l^GO8O{^N!08Gnw7N>NnX)EH+Nua)3Y(c z&{(nX_ht=QbJ%DzAya}!&uNu!4V0xI)QE$SY__m)SAKcN0P(&JcoK*Lxr@P<Bj^D- zi(H(l^zsWRcIm}YCou&G1we!7IMt1dAI3MKk4-3tybIvwniaUWp=||&s9lB&iptb> zY&P=}&B3*UWNlc|&$Oh{BEqwK2+N2U$4WB7Fd|aIal`FGANUa9E-O)!gV`((ZGCc$ zBJA|FFrl<?%m-}hcKbonJcfriSKJrE#oY4SQUGFcnL~;J2>g~9OBp#f7aHodCe{6= zay$6vN~zj1ddMZ9gQ4p32(7wD?(dE>KA2;SOzXRmPBiBc6g`eOsy+pVcHu=;Yd8@{ zSGgXf@%sKKQz~;!J;|2fC@emm#^_rnO0e<D`xKOl)v&1gxhN0@LroTIseY?HHF`U$ zRCxyayrK2fk|YppMxAKP{J=gze_dhnAkmEFp<%l9vvc1zcx#Lz*hP4TNeag4(W!Be zM4c#}`np`hRl02rJ50(%WD@_u_Qk1TUrpL44g>sEn^QxXgJYd`#FPWOUU5b;9eMAF zZhfiZb|gk8aJIw*YLp4!*(=3l8Cp{(%p?ho22*vN9+5NLV0TTazNY$B5L6UKUrd$n zjbX%#m7&F#U?QNOBXkiiWB*_tk+H?N3`vg;1F-I+83{M2!8<^nydGr5XX}tC!10&e z7D36bLaB56WrjL&HiiMVtpff|K%|*{t*ltt^5ood{FOG0<>k&1h95qPio)<rMG98B zE?gDMmn^Zo(`Ek7uvNsnUgUfUfwFF7?z~>2`eL${YAGIx(b4VN*~nKn6E~SIQUuRH zQ+5zP6jfnP$S0iJ<xI2U>@~t!Ai3o`X7biohl<ds?PbGDArmkAV12ldkGzY{P*80E zF=Wk3w#9|J1dAeV)Rlk?%L=ol!+m5%A|(KP`fR=nD^&iHT@Z5DaZ(w0hqfh|V>i;E zT#yXyl{bojG@-TGZzpdVDXhbmF%F9+-^YSIv|<!(knL3!Z+}F~)r$<ET0f@9KVjok zfvU`%FUbk|yAc)S0rB`JBWTLd7hPAAqP2ltlwee5T}#_Gpbl80w-LA;|BD>MT1l3j zrxOFq>gd2%U}?6}8mIj?M<N%?8n+3Rx8(2-`*c@op88}5-iqw*PHkqnj$k8#t^|g> zc077Zc9fq(-)4+gXv?Az26IO6eV`RAJz8e3)SC7~>%rlzDwySVx*q$ygTR5kW2ds- z!HBgcq0KON9*8Ff$X0wOq$`T7ml(@TF)VeoF}x1OttjuVHn3~sHrMB++}f7f9H%@f z=|kP_?#+fve@{0MlbkC9tyvQ_R?lRdRJ@$qcB(8*jyMyeME5ns6ypVI1Xm*Zr{DuS zZ!1)rQfa89c~;l~VkCiH<d?V{)&8(@3=6jm=fW<)H`CSQ9+iNwDH;4S!Xw4H9nux4 zKNscQ&OV9zHF_+cIJ=X)qIF;(!)}sl`hhO)dHz6nA0^W{a9q1^gzxvh-bS1(N273| zq;PSR{n|+%3`+}9Q7}{mC7k)HXlUhkBKH%A@-sEx!4Mlk=^P1dtF=-lC3U?55B}ez z`Fd)kItC)!X+F!>I|PCBd`S*2RLNQM8!g9L6?n`^evQNEwfO@&JJRme+uopQX0%Jo zgd5G&#&{nX{o?TQwQvF1<^Cg3?2co;_06=~Hcb6~4XWpNFL!WU{+CK;>gH%|BLO<b zgJpht0ltX3sE2RJAUcld5MW}&%<sw};dL~bdZ0?zVg~mRcaNBgUZe;8@DKXRQmlOf zAIhHBNh=}LzcTdUnfgd6#GEx350bi`lb)LaBso2CW!*0Xe!UJNwIWeg)QXy=e3bwZ zIJ8=;u}r&BGoF;ftQ-dJ!kBp#;lHIlNwC)v?OHP&#Mh~B%=jdgWQCSqpANGQEkG%n zM?zk5@$%!-gPc55s943P-Mv1>h7@!hsa(>pNDAmpcuVO-?;Bic17R}^|6@8DahH)G z!EmhsfunLL|3b=M0MeK2vqZ|OqUqS8npxwge$w-4pFVXFq$_EKrZY?BuP@Az@(k`L z`<G71X#W|!P3Z{wEvg5Ob7@MbwprRM&*~yi*+R-9I8&p-;yM=Q)z$bTY1}y<i9f;W zGBCz3n1=6)vV6bV+;GN8E|c1rg49&nk_(FLVA<i_4OxA`vE>ViQBSk`y+YwRT;&W| z2e3UfkCo^uTA4}Qmmtqs+nk<f8_TTXgg$0%V(GO^t)<!()wOU}JKa$=7V(Fd-u5kW zfKQU%n`CZ_1jFoAu|=do)|56^VkbaXtt)NlpAubGIJ@ET@k0K*McoNg@OCSSeKJ`( z*rHh**zg=F3rmZ2ux+4MzedRxj4$W0VqcP)lO*|#;Iw4z!Gidd%|ry%SN>#gNr2W4 zTH%hhErhB)pkXR{B!q5P3-OM+M;qu~f>}IjtF%>w{~K-0*jPVLl?Chz&zIdxp}bjx zStp&Iufr58FTQ36AHU)0+CmvaOpKF;W@sMTFpJ`j;3d)J_$tNQI^c<^1o<49Z(~K> z;EZTBaVT%14(bFw2ob@?JLQ2@(1pCdg3S%E4*dJ}dA*v}_a4_P(a`cHnBFJxNobAv zf&Zl-Yt*lhn-wjZsq<9<PjKts@j|?j*H<KG_l+Ikza{2Tyz(8wgaT$KKCTR@fUFh? z9>v-IsXxAxMZ58C@e0!rzhJ+D@9^3~?~yllY^s$?&oNwyH!#~6x4gUrfxplCvK#!f z$viuszW>MFEcFL?>ux*((!L$;R?xc*myjRIjgnQX7<gW>9@UPD$6Dz0jutM@7h_pq z0Zr)#O<^y_K6jfY^X%A-ip>P%3saX{!v;fxT-*0C_j4=UMH+Xth(XVkVGiiKE#f)q z%Jp=JT)uy{&}Iq2E*xr4YsJ5>w^=#-mRZ4vPXpI6q~1aFwi+lQcimO45V-JXP;>(Q zo={U`{=_JF`EQj87Wf}{Qy35s8r1*9Mxg({CvOt}?Vh9d&(}iI-quvs-rm~P;eRA@ zG5?1HO}puruc@S{YNAF3vmUc2B4!k*yi))<5BQmvd3tr}cIs#9)*AX>t`=~{f#Uz0 z0&Nk!7sSZwJe}=)-R^$0{yeS!V`Dh7w{w5rZ9ir!Z7Cd7dwZcK;BT#V0bzTt>;@Cl z#|#A!-IL6CZ@eHH!CG>OO8!%G8&8t4)Ro@}USB*k>oEUo0LsljsJ-%5Mo^MJF2I8- z#v7a5VdJ-Cd%(a+y6QwTmi+?f8Nxtm{g-+WGL>t;s#epv7ug>inqimZCVm!uT5Pf6 ziEgQt7^%xJf#!aPWbuC_3Nxfb&CFbQy!(8ANp<Dkrrv&eXZOx^ui15L`|GC6Zo9J8 zt4l&YYgkq79`qbC=O@Wu>kWLI4oSnH?Q3f?0k1t$3d+lkQs{~(>06l&v|MpcFsyAv zin6N!-;pggosR*vV=DO(#+}4ps|5$`u<dyVk_IJiOQUOA<$>dE%Kdmp?G7B#y%<bi zGVk-OWo?nx8M9(n3)OkC>H`R|i8skKOd9Xzx8xgR$>Zo2R2Ytktq^w#ul4uicxW#{ zFjG_RNlBroV_n;a7U(KIpcp*{M~e~@>Q#Av90Jc5v%0c>egEdY4v3%|K1XvB{O_8G zkTWLC>OZKf;XguMH2-Pw{BKbFzaY;4v2seZV0>^7Q~d4O=AwaPhP3h|!hw5aqOtT@ z!SNz}$of**Bl3TK209@F=T<Nh*u*7J=P_EEnnD=hbiG0v_)iQwN<!vDIogn=iGRs3 zt_h!RUdkzWHMpc*d}k%tjHimct$!p&AH8pRZ+FJo|9w~+h(n#lp$57vBXGLddx*%@ z5%Aj-8?hH;TIkF9$}Pwu0)KjO*p&uKv6>n1+mgZa8yh(Png%Zd6Mt}^NSjy)etQrF zme*llAW=N_8R*O~d2!apJnF%(JcN??=`$qs3Y+~xs>L9x`0^NIn!8mMRFA_tg`etw z3k{9J<p4JZCS-C}49WuHGGruT=x>Ajnl@ygIiJcNHTy02GMAvBVqEss&t2<2mnw!; zU`J)0>lWiqVqo|ex7!+@0i>B~BSU1A_0w#Ee+2pJx0BFiZ7RDHEvE*ptc9md(B{&+ zKE>TM)+Pd>HEmdJao7U@S>nL(qq*A)#eLOuIfA<xx)>S@j`_sK0UEY6OAJJ-kOrHG zjHx`g!9j*_jRcJ%>CE9K2MVf?BUZKFHY?EpV6ai7sET-tqk=nDFh-(65rhjtlKEY% z@G&cQ<5BKatfdA1FKuB=i>CCC5(|9TMW%K~GbA4}80I5%B}(gck#Wlq@$nO3%@QP_ z8nvPkJFa|znk>V92cA!K1rKtr)skHEJD;k8P|R8RkCq1Rh^&}Evwa4BUJz2f!2=MH zo4j8Y$YL2313}H~F7@J7mh>u%556Hw0VUOz-Un@ZASCL)y8}4XXS`t1AC*^>PLwIc zUQok5PFS=*#)Z!3JZN&eZ6ZDP^-c@StY*t20JhCnbMxXf=LK#;`4KHEqMZ-Ly9KsS zI2VUJGY&PmdbM+iT)zek)<hjl_Ql0Z<Zn_qAb)m1SGqs~RuzvnShAB@_vF{e+592q z$DB!xBIZfcH*9&k=wlV*!)l9TjLaF6{FU=1emb_fuvC;885YA6nM5}UqhPTc%&*tY z3h;oOpGO3Hx+t7EjPYfzaZ}+D=ndS&SDnV=GA-}a=$GiNOi~a`1gJao%JzT9!|NX9 z<CC9{n}y#@=&Y6rk@_w$wqbKs!E-bTFZW}3bqJ;f!@40M^ykqGs3;>#Qc#_i4uH43 z@T5SZBrhNCiK~~esjsO9!qBpaWK<`>!-`b71Y5R<QKZFC;tbrvH*7OQFB+SCa^&~y zposW2PUqn>eXQ4AJU~T<enI;Gq30%Z%SsfHco3Z`w^cm#%0^~onRV&P&#QErx)JwE z+PM!k!qYC}ESrBrHoDQz*X1YmFa#(SZW<AV$!J0LWu4IDbZ2bw=%%Iq9Hg*REoc?; z{E60bn(-sNYKAv{(YDGA5Ne~oOSP*!BJYblyeWN+CVy8q4{fMj;2#8%D!ii%2bR=s z%l;FFHzQ~S|A8UKuFT*34q|LzMc~~o#;)Kw9DtS!bp3JQi_@L6HQjXe7-;AjHEUja z>2Njri1CEp5oKw;Lnm)-Y@Z3sEY}X<ceQi^_CPpPY_VEPYF+%Om#`r)SPUG}UXq2Y zpr9=;`h)oB6MR*Xk2Eh4r7Hb|{>IgSy%xo=uek(kAAH5MsV$V3uTUsoTzxp_rF=tx z<QsYQ(;?5S(qGqiH7>V07vlJNKtJhCu`b}*#m&5LV4TAE&%KtHViDAdv#c^x`J7bg z&N;#I2GkF@SIGht6p-V}`!F_~lCXjl1BdTLIjD2hH$J^YFN`7f{Q?OHPFEM$65^!u zNwkelo*5+$ZT|oQ%o%;rBX$+?xhvjb)SHgNHE_yP%wYkkvXHS{Bf$OiKJ5d1gI0j< zF6N}Aq=(WDo(J{e-uOecxPD>XZ@|u-tgTR<972`q8;&ZD!cep^@B5CaqFz|oU!iFj zU0;<Kr(xN%j}{P50=dczD~4jn(p0D1`)Q|ld@m)3cU?5-DDA%Lq4Vd2?$jcNa3@4} zt0;5Pk0HJXk<P(S=!%ZtD121Ne##d}^nRI9>6fQX&~15E53EW&w1s9gQQ~Zk16X%6 zjG`j0yq}4deX2?Tr(03kg>C(!7a|b9qFI?jcE^Y>-VhudI@&LI6Qa}WQ>4H_!UVyF z((cm&!3gmq@;BD#5P~0;_2qg<pD9=9nXg$TuH}wQh9<MTT}D~YJ$+K3jbd)SV}wix zf+zmLDPNc@nH3C;GngJH(K9z-$bm-ym&hXvg&{t=h}^v&Zpkgh>ZhtJS|>WdtjY=q zLnHH~Fm!cxw|Z?Vw8*~?I$g#9j&uvgm7vPr#&iZgPP~v~BI4jOv;*OQ?jYJtzO<^y z7-#C={r7CO810!^s(MT!@@Vz_SVU)7VBi(e1%1rvS!?PTa}Uv`J!EP3s6Y!xUgM^8 z4f!fq<3Wer_#;u!5ECZ|^c1{|q_lh3m^9|nsMR1#Qm|?4Yp5~|e<cTgyd3~1T9l&* zeQ01<P2U~{V&q4>r2?W^7~cl;_r4WSme_o68J9p03~Hc%X#VcX!xAu%1`R!dfGJCp zV*&m47>s^%Ib0~-2f$6oSgn3jg8m%UA;ArcdcRyM5;}|r;)?a^D*lel5C`V5G=c~k zy*w_&BfySOxE!(~PI$*dwG><<WF75p<o9EVVze~dTW<Z_^0lybcm7u?o5{_6x)ND; zb8GQ#!>+-%KT5p?whOUMA*k<9*gi#T{h3DAxzAPxN&Xws8o9Cp*`PA5>d9*Z-ynV# z9yY*1WR^D8|C%I@vo+d8r^pjJ$>eo|j>XiLWvTWLl(^;JHCsoPgem6PvegHb-OTf| zvTgsHSa;BkbG=(NgPO|CZu9gUCGr$8*EoH2_Z#^BnxF0yM~t`|9ws_xZ8X8iZYqh! zAh;HXJ)3P&)Q0(&F>!LN0g#bdbis-cQxyGn9Qgh`q+~49Fqd2epikEUw9ca<Icy-f zOt40c5j7j)$)tP9?uvS*(MhNoK9DyuR}iw#hq(_Yg;FQNx_fxU*Eu(iTCigNUM7t< z>M%V6WgP)532RMRW}8gNS%V%Hx7apSz}tn@bQy!<=lbhmAH=FsMD?leawbnP5BWM0 z5{)@EEIYMu5;u)!+HQ<i|FmCtfdneL-c-Zq4Plvb%6L#`yCeba4_fn4B8J3*R<jzl zfvYN4K`&;0Sxn>WhQ;D3_Cm_NADNeb-f56}<{41aYq8p4=93d=-=q0Yx#knGYfXVt z+kMxlus}t2T5FEyCN~!}90<Qw*O-2+V!RyNwDJ!D4}()%&9a2ilTUH&u5D!U%eI_q zx}xGi`t`GnBsEW*ontVcR-ikx88LbjAhe<X@Zi_w7Y34lxFFrZ2Q&%wKjDtka2LVK zHc8~1#H%sr<^E7ZD2HEuJ^9vl!WfP^A{M0b1kd0=9ymV8H)Sd)K8ApeV;=DNu1w7T zq3y-B$08B=*qJh`RBSq*hM$V1Wi(wSS$C7SwYBw1{q+D%@|+@4!e&J2mmVQuQ$1nJ zGVp>O_X@@PQpuy;kuGz@bWft%diBTx?d)_xWd_-(!LmVrh**oKg!1CNF&LX4{*j|) zIvjCR0I2UUuuEXh<9}oT_zT#jOrJAHNLFT~Ilh9hGJPI1<5`C-WA{tUYlyMeoy!+U zhA#=p!u1R7DNg9u4|QfED-2TuKI}>p#2P9--z;Bbf4Op*;Q9LCbO&aL2i<0O$ByoI z!9;Ght733FC>Pz>$_mw(F`zU?`m@>gE`9_p*=7o=7av`-&ifU(^)UU`Kg3Kw`h9-1 z6`e6+im=|m2v`pN(2dE%%n8YyQz;#3Q-|x`91z?gj68cMrHl}C25|6(_dIGk*8cA3 zRHB|Nwv{@sP4W+Y<?>ZM)VKI>R<dU=sQkg7!lDS83Q3{+&sk$J+O!cATJ_o5Pb&W_ z)bdtK2>lB`n=Oj~Rzx~M+Khz$N$45rLn6k1nvvD^&HtsMA4`s=MmuOJID@$s8Ph4E zAmSV^+s-z8cfv~Yd(40Sh4JG#F~aB>WFoX7ykaOr3JaJ&Lb49=B8Vk-SQT9%7TYhv z?-Pprt{|=Y5ZQ1?od|A<_IJU93|l4oAfBm?3-wk{O<8ea+`}u%(kub(LFo2zFtd?4 zwpN|2mBNywv+d^y_8#<$r>*5+$wRTCygFLcrwT(qc^n&@9r+}Kd_u@Ithz(6Qb4}A zWo_HdBj#V$VE#l6pD0a=NfB0l^6W^g`vm^sta>Tly?$E&{F?TTX~DsKF~poFfmN%2 z4x`Dc{u{Lkqz&y!33;X}weD}&;7p>xiI&ZUb1H9iD25a(gI|`|;G^NwJPv=1S5e)j z;U;`?n}j<Q^Xq~o28<9wN;wOTm1lpjZMh*aUX(~T_Y3#ZnG~Ye&HG?FC8<&_!tool z+@`jls~3x-4`e?M70izyrpLQDV~@R;Ddqa8ubupC&5hxJ!0Qn2&@6(rv>nY6rA{V^ zxTd{bK)Gi^odL3l989DQlN+Zs39Xe&otGeY(b5>rlIqfc7Ap4}EC?j<{M=hlH{1+d zw|c}}yx88_xQr`{98Z!d^FNH77=u(p-L{W6RvIn40f-BldeF-YD>p6#)(Qzf)lfZj z?3wAMtPPp>vMehkT`3gToPd%|D8~4`5WK{`#+}{L{jR<c)T{dJNa_2~nx}yzR>UMt zrFz+O$C7y8$M&E4@+p+o<?<4i!4ikchlAhrd(TAazwXC#eTotZ4)SbD2SX9vq+(V^ zQt>V5c%uYzbqd2Y%SSgYy#xh4G3hQv>V*BnuKQhBa#=o<cI|?w3{ulWOpdl|%RYTA zSx@6KnTs$R(CM2sHs-QJn!^oj_3M4<ToCw0Dysc#3eTjWBJ-T+adb-$?`_4mF<8?g zSKY1V7KhH!;LK22fSg)B*<uJ7m~6W3CUps0^d9*o2V_Gub>ZB~w{azUB+q%bRe_R^ z>fHBilnRTUfaJ201czL8^~Ix#+qOHSO)A|xWLqOxB$dT2W~)e-r9;bm=;p;RjYahB z*1hegN(VKK+ztr~h1}YP@6cfj{e#|sS`;3tJhIJK=tVJ-*h-5y9n*&cYCSdg#EHE# zSIx=r#qOaLJoVVf6v;(okg6?*L_55atl^W(gm^yjR?$GplNP>BZsBYEf_>wM0Lc;T zhf&gpzOWNxS>m+mN92N0{;4uw`P+9^*|-1~$<g_U{SU`H<rGXK<wL9(P>uXpggj4- z^SFc4`uzj2OwdEVT@}Q`(^EcQ_5(ZtXTql*yGzdS&vrS_w<Vq*ng}zPHZxXbJ~5By z5q!Q1MEDSMNOWX9zY-~b`9@lU+AIe>>~~ra|Nb5abwf}Y!uq6R5f&6g2ge~2p(%c< z@O)cz%%rr4*cRJ5f`n@lvHNk@lE1a*96Kw6lJ~B-XfJW%?&-y?;E&?1AacU@`N`!O z6}V>8^%RZ7SQnZ-<!aS@7Sy5FdEA^NVBSolPfAv!POl_VDW*<OY|VOa1x+Nt4h}kC zF5f5bMcr5zsZz*#rv_qyg5_y;>z$(jsX`amu*5Fj8g!3RTRwK^`2_QH<oOlcTv0T* zq^FmDESBJUwy8>e;_2y_n|6gSaGyPmI#kA0sYV<_qOZc#-2BO%hX)f$s-Z3xlI!ub z^;3ru11DA`4heAu%}HIXo&ctujzE2!6DIGE{?Zs>2}J+p&C$rc7gJC<HidCCr+8PF zWiTVZ>35gxhflorvsb%sGOxpuWhF)dL_&7&Z99=5M0b~Qa;Mo!j&Ti_kXW!86N%n= zSC@6Lw>UQ__F&+&Rzv?gscwAz8IP!n63>SP)^62(HK98nGjLY2*e^OwOq`3O|C92? z;TVhZ2SK%9AGW4ZavTB9?)mUbOoF`V7S=XM;#3EUpR+^oHtdV!GK^nXzCu>tpR|89 zdD{fnvCaN^^LL%amZ^}-E+214g&^56rpdc@yv0b<3<Gcz@z*K79?oK~*UzGlKFJXT z{XOryj|k?!nDS(G1LtLxYD^Cq?c?_!zYn!x^#tLjQ6=Wb!)yrQsQW$6U<7{9%v7a- zv*ocK5QN4V3`xVyd7lYi<tse4LzLtbxdam8l#%xfBL@jXus_3m`H&T(SG4<1{Xtfu zMb*~2c3zevaj8sJ+%2=tK7#q$!xF@Xc_%7Ws0|ayo4RjQhmCcKBx<ij=1uikr$^Pt z9|pP=(@t-<MX5uDFk4~}Y&YCR_($i(L2tZ?=zYb8^M2`}T)&sKMTvyh6Hf2vk#&E} zXFWd3BT@?-Qm?6K=3M(cZ#LOR`xDd$o~J$T>}Ys?)f|fXN4oHf$six)-@<;W&&_kj z-B}M5U*1sb4)77aR=@%I?|Wkn-QJVuA96an25;~!gq(g1@O-5VGo7y&E_srxL6ZfS z*R%$gR}dyONgju*D&?geiSj7SZ@ftyA|<I`YtD1a%3oCr%5@GGkBtN{5mnwPyOw=G z)5mh1d5f2bd0O6v9}uRb?jQWt0Hmbh{Lw~%;q96e<JYrfUt;Ww3`|kuk8YLozMnJA zL-%S-b>}(*Y4KbvU!YLsi1EDQQCnb+-cM=K1io78o!v<D2B&P2)99nqSy|&vmf_z? z=eWr~Nb^z}4FA|*1-U>*);o<<Bb~caN#d%78rHzz&LtUD8*+uiPJdUJ<!gd#RBLsK z$C!13l?*$0KTH~HOk{`~({IY19$^eGtD0+`Ng;Krabee-ZmxY?a!#sR^lIs7X@lqE z)iFHx46*Kc<U3%gK1Qg`N*=%M8g<Qr@DDqezg1<>XwjaQH%)uIP&Zm?)Nfbfn;jIr z)d#!$gOe3QHp}2NBak@yYv3m(CPKkwI|{;d=gi552u?xj9ObCU^DJFQp4t4e1tPzM zvsRIGZ6VF+{6PvqsplMZWhz10YwS={?`~O0Ec$`-!klNUYtzWA^f9m7tkEzCy<_nS z=&<(awFeZvt51>@o_~>PLs05CY)$;}Oo$VDO)?l-{CS1Co=nxjqben*O1BR>#9`0^ zkwk^k-wcLCLGh|XLjdWv0_Hg54B&OzCE^3NCP}~OajK-LuRW53CkV~Su0U>zN%yQP zH8UH#W5P3-!ToO-2k&)}nFe`t+mdqCxxAHgcifup^gKpMObbox9LFK;LP3}0dP-UW z?Zo*^nrQ6*$FtZ(>kLCc2LY*|{!dUn$^RW~m9leoF|@Jy|M5p-G~j%+P0_#orRKf8 zvuu5<*XO!B?1E}-*SY~MOa$6c%2cM+xa8}_8x*aVn~57v&W(0mqN1W`5a7*VN{SUH zXz98DDyCnX2EPl-`Lesf`=AQT%YSDb`$%;(jUT<emmKF_zfZmU9B12q_dyZ<_@h~k zvEq1`Vx6X|zFHC1f>rNen$NPJrlpPDP}prI>Ml!r6bCT;mjsg<oj3+@ct5lWE*J;5 z4E~(;FwK{V8;n^S+p_aly?)G^7&y`S%eK)TJhe8?@}L_b8H};V-{Fr!7~z`5Jn&~y zle5N-{eo+>@X^#&<}CGf0Jt<ps|x+2W>R{Ecwd&)2zuhr#nqdgHj+g2n}GK9CHuwO zk><uMX@X}I+5rrj?NaO6BMSeLuD{-~8R-Gl2xdC9#?M&n3M8$1#r~F<bd_yU6EE{Y z#eCFVb$%8`qmYLY$VN_bTcap4)*3IM0tVFqt0C)EHHU4$9K2ap4$RYn7cYx68f*63 zqjgq9d3s#J0z)IOp-dbsoyDl3q&F;wDIxirPuXzvw6-Mhm_%B8`dB@kd7fLXw-%?$ zoq?`st6r0!H5QKHrVxu9;wFCr4k6@&eG$(7Z2Wi#T=t;uR8LkI#eWjbL4#SB+RR!} zkvLwWmhxM!7BIsi5NeXcxeg6+4^H8NJB5=2mJzA06v|{=fl0X|ig2$)&h*GM&JpHp zr`8`GjG!&l9EyWchuo>oZxy{v<eHuSsx&-tHadS1q^a4f?|RTjYB^sRK14!iW+^lB z!ebp33Hf8OUb(D`D*|G{AftC98wHP4tb?H!)=@9haZJ)F+0;HQc5`Qlnk&U!fz)-9 z%lX#G)XFlYmyE^D)O;h749_^`>cOL)$8-}L^iV<p27<5%t|ClWJe$Rd_|U|Ck(u@6 zTgwrC&(m^cFeKDxIl7TOJH#1Wo==_x;yAITBFJ1z$*I>fJHAGfwN$prHjY<ZwGVKY zZ8+b}fUD+>V0ju}8%jWquw>}_W6j~m<}Jf!G?~r5&Rx)!9JNX!ts#SGe2HzobV5); zpj@&`cNcO&q+%*<%D<T}5E&SDWDa4Lg;*h`<xw$&SGrTg$|CXl_i7+njSd+)yvyz7 z+0<o|PMTJL)R>7za|?m5qlmFK$=MJ_iv{aRs+BGVrs)98BlN^nMr{V_fcl_;<BiuS ztTFCwthZrVHPPZYBIYp#EouQ9MTH{-OaLh9+PRHAG3=cqP}nnZd8AjsX8sR)@*@Na z!0>jkzRju+c-y?gqBC_@J0dFLq-D9@VN&-`R9U;nv$Hg?>$oe4N&Ht$V_(JR3TG^! zzJsbQb<dCovVFFYER#ii{pf+`)Dd4mJA8V_i{)g*7b35$IR9(S%Er0t1yr7X5aERc zeK=jG4aV7X*X+)C@a&31a^^wDy<E&Lu}Ry(`Um&dxXGiHJfU<|q(iByYWWLIS^^>i zFE6-{#9{G{+Z}ww!ycl*7rRdmU#_&|DqPfX3CR1I{Kk;bHwF6jh0opI`UV2W{*|nn zf_Y@%wW6APb&9Rr<YY$Si*BvV^N#m{QYOko?PXQXU(La}0lCv3qWQ$bi`=<yuf89@ zA3M_;xKTP6E^K#?{F`hD*rTDZhZ!h73@a^*&yKH>bEN=PQRBEpM(N1w`81s=(xQj6 z-eO0k9=Al|>Ej|Mw&G`%q8e$2xVz1v4DXAi8G};R$y)ww638Y=9y$ZYFDM$}vzusg zUf+~BPX>(SjA|tgaFZr_e0{)+z9i6G#lgt=F_n$d=beAt0Sa0a7>z-?vcjl3e+W}+ z1&9=|vC=$co}-Zh*%3588G?v&U7%N1<wSL*V~9}~r(eJ^+Xr3`-m(Sj@@;y|({lFw zG+a0jI%A@viPJ_TgyiV93C-_fon>Qf-wNWJ)(v`iO5KHSkC5&g7CrKu8V}uQGcfcz zmBz#Lbqwqy#Z~UzHgOQ;Q-rPxrRNvl(&u6ts4~0=KkeS;zqU<rCYLCOgtuj&A3yvF z)|<)nA^eF$@T!K+ig@JbUkyVVJP%Y)>Rz%!-ERppmd%0v>iRlEf+H$yl{_8TMJzo0 z>n)`On|7=WQdsqhXI?#V{>+~}qt-cQbokEbgwV3QvSP7&hK4R{Z{aGHVS3;+h{|Hz z6$Js}_AJr383c_+6sNR|$qu6dqHXQTc6?(XWPCVZv=)D#6_;D_8P-=zOGEN5&?~8S zl5jQ?NL$c%O)*bOohdNwGIKM#jSAC?BVY={@A#c9GmX0=T(0G}xs`-%f3r=m6-cpK z!%waekyAvm9C3%>sixdZj+I(wQlbB4wv9xKI*T13DYG^T%}zZYJ|0$Oj^YtY+d$V$ zAVudSc-)FMl|54n=N{BnZTM|!>=bhaja?o7s+v1*U$!v!qQ%`T-6fBvmdPbVmro&d zk07TOp*KuxRUSTLRrBj{mjsnF8`d}rMViY8j`jo~Hp$fkv9F_g(jUo#Arp;Xw0M$~ zRIN!B22~$kx;QYmOkos@%|5k)!QypDMVe}1M9tZfkpXKGOxvKXB!=lo`p?|R1l=tA zp(1}c6T3Fwj_CPJwVsYtgeRKg?9?}%oRq0F+r+kdB=bFUdVDRPa;<s*Z4&z%Yqy%U zOeHw$WK*_?C+%QKv}yj&a(!5Ni>E~~>2$w}>O>v=?|e>#(-Lyx?nbg=ckJ#5U6;RT zNvHhXk$<cTrzyFrc-kzJ80|Sr7cPKJYnxQh*Fg9@b51h^!>P}m9wSvFyU3}=7!y?Y z=fg$PbV8d7g25&-jOcs{%}wTDKm>!Vk);&rr;O1nvO0VrU&Q?TtYVU=ir`te8SLlS zKSNmV=+vF|ATGg`4$N1uS|n??f}C_4Sz!f|4Ly8#yTW-FBfvS48Tef|-46C(wE<BN zM?~(EkSJJWr_!W7-HptZRmK`p&C>O_%pPhUC5$-~Y?!0vFZ^Gu`x=m7X99_?C-`|h zfmMM&Y@zdfitA@KPw4Mc(YHcY1)3*1xv<iSQWzdA1>W9V-r4n-9ZuBpFcf{yz+SR{ zo$ZSU_|fgwF~aakGr(9Be`~A|3)B=9`$M-TWKipq-NqRDRQc}ABo*s_5kV%doIX<z zw8f$0lCeVGD0^!OedVm2t32)213YQ46v=o)@UsVzy`KZ%hr__m!jsQbd@}{{Vg1hz z`m2-BpqxgapTIephm4Cik^T6BeWfmt%BA@BRlvqT0ILcR0(vVdxD!}~F3BI!@Yuk* zM2~`l5+!SvcPoj}AC@Q9McO3!2ke!m5VcW3F%a(IA*N@sL73(w3O(3~t5el4Dq{JU z21IfDfV)n^u4cGvvfJlGe~Q~Yzeudy#8j^ja>7LRLRau_gd@Rd_aLFXGSU+U?uAqh z8qusWW<lz^u{++i(BMS0kYpMurHwdx8=v!VDug!+!?SoQ%5#Z9_%%XQ)=}5@(OGY$ z!*NFRMlh?b0mZ-o&{hRY(q#;?AsyI_fTbU3vvt{86Gd^<UxrFKXriAuhLyoz-Rb+| z<1fH@C7QEgQz2VdIb}M#v@~+roe%YIUs5B>cvgQ&wu{|sRXmv?sl=xc<$6AR$+cl& zFNh5q1~kffG{3lDUdvEZu5c(aAG~+64FxdlfwY^*;JSS|m~CJusvi-!$XR`6@XtY2 znDHSz7}_Bx7zGq-^5{stTRy|I@N=>*y$zz>m^}^{d&~h;0kYiq8<^W<E|75Z!A4X; zB0ckyjy2crb1=uu;OnTA+AN(`$!y~N){ZywsrcJ<-RJ-6@#;QH|7$vRI{)h?@p2NX z`N+$B?J?QE9;Pm%%)e)K9b55SBEW5@Zc4|{XhN6&8tG6ODyNFgS%k;enJu!|jBjTn zO3=N;{~$Us+^lM79~#+NVdMuMV*xv4<srsN5l%(Xfx|TFiWsSLu6VKb8+BQX%9T6) zLIA<^s*!o98&YNSoO#lh*yl=4IaXWU@%j6|nHVJL2?PUhARrz8&IkW*Q<47%jpzTI z4gPog-xBcuLB=pm_-|9W&~MFVz_3-f?M6(XIxnIg#$zC^5E`10kVD2)wtP_r+-MVn zDB)nM192c6VQ(1fw5pgW;z9QPF|WVy-Pi3Kqyd;SXdDvK@g#36c@VC&u=_B=n%w}x z9G42<h(@l93n9W)B(s=&>q7Dz0w31ShO^~LUfW6rfitR0(=3;Uue`Y%y@ex#eKPOW zO~V?)M#AeHB2kovn1v=n^D?2{2jhIQd9t|_Q+c|ZFaWt+r&#yrOu-!4pXAJuxM+Cx z*H&>eZ0v8Y`t}8{TV6smOj=__gFC=eah)mZt9gwz>>W$!>b3O;Rm^Ig*POZP8Rl0f zT~o=Nu1J|lO>}xX&#P<uNYpwDdsi81$~7Dv-8cIS(lR52^!TF;6k;WMGV`thcu^6S z@T3rgu^2l&lSgk|u&dqJ2P;_lKd-gsz+E~nyy$zL@l8HyyxzgF#YH#@jXdT>58%Yl z83`HRs5#32Qm9mdCrMlV<JBDhyZ+y^N%S92djDerOElqpRE}K*p`=oMP>|NKNC+Z~ z9OB8xk5HJ>gBLi+m@(pvpw)<om*<*&g*ukIpJ5#uX6#7U*X+*MN|7vZ8*HK)=`Y9r z)#d;zRimk{mmRK`xtmKSn@imtSD%un-#&@aHsi(XFSqmU+t2^tlw;mwe}X*y&#AIH zlv#=?W?e4tr=1o`K<LAS)WBGaORGt!_L??}o8QF5X|ARAXjcw9(=`^ih&uvZ?3o=4 ztCfj-M@ZND9Dnt(PEoh14OzzWaAN5QQ)tU}4*nXvp1HQ^w*zt7KrnA5B`0hYyAdFC zH+>1(OaVJKs*$Ou#@Knd#bk+V@y;YXT?)4eP9E5{J%KGtYinNYJUH9PU3A}66c>Xn zZ{Bn0<;8$WCOAL$^NqTjwM?5d=RHgw3!72WRo0c;+houoUA@HWLZM;^U$&sycWrFd zE7ekt9;kb0`lps{>R(}YnXlyGY}5pPd9zBpgXeJTY_jwaJGSJQC#-KJqmh-;ad&F- z-Y)E>!&`Rz!HtC<wKL>z>%yO<y&s#nmyWumg2@9<En(?C^(|rjP3fstXvL7F_}@s~ zK?}vRELPAe=@^SDzf;4gMIY~6wbR)ERQj~L^17FRR>J|v(u7P*I$jqEY3}(Z-orn4 zlI?CYKNl`6I){#2P1h)y(6?i;^z`N3bxTV%wNvQW+eu|x=kbj~s8rhCR*0H=iGkSj zk2<D*!UmdR0qg)7cV>3lr9kr|p7#qKL=UjgO`@UnvzU)`&fI>1Qs7ubq{@+lK{hH* zvl6eSb9%yngRn^T<;jG1SVa)eA>T^XX=yUS@NCKpk?ovCW1D@!=@kn;l_BrG;hOTC z6K&H{<8K#dI(A+zw-MWxS+~{g$tI7|SfP$EYKxA}LlVO^sT#Oby^grkdZ^^lA}uEF zBSj$weBJG{+Bh@Yffzsw=HyChS(dtLE3i*}Zj@~!_T-Ay7z=B)+*~3|?w`Zd)Co2t zC&4DyB<B`NVJ>!o&YgSw+fJn6`sn$e)29`kUwAc+1MND7YjV%lO;H2}fNy>hD#=gT ze+-aFNpyKIoXY~Vq-}OWPBe?Rfu^{ps8>Xy%42r@RV#*QV~P83jdlFNgkPN=T|Kt7 zV*M`Rh*30&AWlb$;ae130e@}Tqi3zx2^JQHpM>j$6x`#{mu%tZlwx9Gj@Hc92IuY* zarmT|*d0E~vt6<+r?W^UW0&#U&)8B6+1+;k^2|FWBRP9?C4Rk)HAh&=AS8FS|NQaZ z2j!iZ)nbEyg4ZTp-zHwVlfLC~tXIrv(xrP8PAtR{*c;T24ycA-;auWsya-!kF~CWZ zw_uZ|%urXgUbc@x=L=_g@QJ@m#5beS@6W195Hn7>_}z@Xt{DIEA`A&V82bc^#!q8$ zFh?z_Vn|ozJ;NPd^5uu(9tspo8t%&-U9Ckay-s@DnM*R5rtu|4)~e)`z0P-sy?)kc zs_k&J@0&0!q4~%cKL)2l;N*T&0;mqX5T{Qy60%JtKTQZ-xb%KOcgqwJmb%MOOKk7N zgq})R_6**{8A|6H?fO+2`#QU)p$Ei2&nbj6TpLSIT^D$|`TcSeh+)}VMb}LmvZ{O| ze*1IdCt3+yhdYVxcM)Q_V0bIXLgr6~%JS<<&dxIgfL=Vnx4YHuU@I34JXA|+$_S3~ zy~X#gO_X!cSs^XM{yzDGNM>?v(+sF#<0;AH^YrE8smx<36bUsH<L8f?5hvib^(w-z zQO~nQ$dVU0i#a3ki#~Zfn+z)A0X6&+uTO~YY-95PED8rYa#tnOB_5j0D(OiyL`p9s zv+IJ_k!HYz5YcKEc7QF88Nvot?2oM%4aDY1Bzw#ErO+K${;d;Xz}Qst%^Hxe<y|{# z0i<}um0l#qNYBrEHp~^dRc(MW&*nx$<xOZo&ngs@b)HTJL5#EBLw4XB%N{_Unwz1| zV8i$e7agBMpxq^UD+OBzpAA4~Wm`dImRWzuo^(m(ArJer$O=jb))nZ!p#}ai;I|`b zxh~i8wmS;I?uK@A5wM9(c}p9|(M`BOW}{O$gH|yS=WST0IY5xeK;n^|OTOu06VXGL ziLV81^Z>bN#y57K8WEu(`qHvQ6cAZPo=J5C(lSmUCZ57Rj6cx!e^rfaI5%w}unz}4 zoX=nt)FVNV%QDJH`o!u9olLD4O5fl)xp+#RloZlaA92o3x4->?rB4`gS$;<QP`qnB zxyR|2?xCkFimDvX6HOV?^)Ex~)EDlr;3{Zk;-f=p?%7c@-P$(ps9BR^)$rFZsteaA z;pEqzR194rw0JOm6L~PJ9F(nNaRn+j%W1SvOz`}E|6u-%XnRuFO#whbo=$_b&QmEc zz35A#zc{~jeDG0s#(%Oyh`}`Lr28fKNg=;!oXo#n2s2b!wHSqmp4gLtkq~?+{}p*~ zmyPE6L~1+ln$95dm03gaCX?Mx^?0LvGdEce@^Fw=4Li}NJ(PPrnJG8UTM7f;`bHcw z$Z`@wnD>WO{R;Z3>cG3IgFX2EA?PK^M}@%1%A;?f6}s&CV$cIyEr#q5;yHdNZ9h{| z-=dX+a5elJoDo?Eq&Og!nN6A)5yYpnGEp}?=!C-V)(*~z-+<AB{~}$sb=b_3)fww3 z1aC=mU#wAjt*hH!O=_Rq0hO_a&wY#~Xao9@|NW*<bx}+viW;viI*Z+I?~t{%B+v(! zDDr@@d60%bC|=S0vZozViq<m)h@uyR_WM|>?kY1Q7qs#Rsy%hu_60rdbB+QQNr?S1 z?;xtjUv|*E3}HmuNyB9aFL5H~3Ho0UsmuMZELp1a#CA1g`P{-mT?B<X1H9ohvAM^; z+8=gDne1h_tC$>chuLEtK}!QZ=3AWakRu~?f9V~3F;TV`5%9Pcs_$gq&CcU}r8gOO zC2&SWPsSG{&o-LIGTBqp6SLQZPvYKp$$7L4WRRZ0BR$Kf0I0SCFkqveCp@f)o8W)! z$%7D1R`&j7W9Q9CGus_)b%+B#J2G;l*FLz#s$hw{BHS~WNLODV#(!u_2Pe&tMsq={ zdm7>_WecWF#D=?eMjLj=-_z`aHMZ=3_-&E8;ibPmM}61i6J3i<Ry9$0oO(dC+M{8z zs~&fm$9WhF63%!K_Mm6jbUbs_bSm8+)$j`QmCxcnfVz-~LWI0Pvt$(Iiice=m6f#A znKpqTEVc`=3la-JE~IF8T$O7$xw2vGNtATg%;ITCJQ$<SdLX>s*=dKf%HC>=xbj4$ zS|Q-hWQ8T5mWde6h@;mS+?k=89?1FU<%qH9B(l&O>k|u_aD|DY*@~(`_pb|B#rJ&g zR0(~(6<MTX1VH`>8fpUPz6TdS@4JT5MOPrqDh5_H(eX1$P2SQrkvN8sTxwV>l0)Qq z0pzTuvtEAKRDkKGhhv^jk%|HQ1DdF%5oKq5BS>szk-CIke{%js?~%@$uaN3^Uz6Wf z_iyx{bZ(;9y4X&>LPV=L=d+A}7I4GkK0c1Xts{rrW1Q7apHf-))`BgC^0^F(>At1* za@e7{lq%yAkn*NH8Q1{@{lKhRg*^TfGvv!Sn*ed*x@6>M%aaqySxR|oNadYt1mpUZ z6H(<Ni{=BqKRj2FW+}Co`K?u{@WLS%pQm3TU}Q0c616}yg+(R+@sl}k&>rupHYf&Z z29$5g#|0MX#aR6TZ$@eGxxABRKakDYtD%5BmKp;HbG_ZbT+=81E&=XRk6m_3t9PvD zr5Cqy(v?gHcYvYvXkNH@S#Po~q(_7MOuCAB8G$a9BC##gw^5mW16cML=T=ERL7wsk zzNEayTG?mtB=x*wc@ifBCJ|irFVMOvH)AFRW8WE~U()QT=HBCe@s$dA9O!@`zAAT) zaOZ7l6vyR+Nk_OOF!ZlZmjoImKh)dxFbbR~z(cM<ohJsx2;$$S(LMO!JiV@-OGlmm z`NdjOOy9O@m26&M`?ASmTQ{@=-K%#U)U7w<-rclq>hfeX1l7S_`;h|v3gI}<v)x_w zvu)Dq)`qX%>n9$sSQ>+3@AF<e#LTCwgPu=4ybha;DXu-e#IUo*sWeYFrWHoigJs{Q zYu_ff&j$_|OP<X2&rv4d2FV^~F@43}*F8@FN!r^c>Ay9=B_y$)q;Wdl|C-X|VV3w8 z2S#>|5dGA8^9%Bu&fhmVRrTX>Z7{~3V&0UpJNEl0=N32euvDGCJ>#6dUSi&PxFW*s zS`}TB>?}H(T2lxBJ!V#2taV;q%zd6fOr=SGHpoSG*4PDaiG0pdb5`jelVipkEk%FV zThLc@Hc_AL1#D&T4D=w@UezYNJ%0=f3iVRuVL5H?eeZM}4W*bomebEU@e2d`M<~uW zf#Bugwf`VezG|^Qbt6R_=U0}|=k;mIIakz99*>FrsQR{0aQRP6ko?5<7bkDN8evZ& zB@_KqQG?ErKL=1*ZM9_5?Pq%lcS4uLSzN(Mr5=t6xHLS~Ym`UgM@D&VNu8e?_=<G2 z$Y^_uSNUz|Ag`4k$;;4dC>nSFtF$u@hpPSmI4Vo_t&v?>$~K4y(O~Rb*(MFy_igM7 z*~yYUyR6yQgzWnWMUgDov!!g=lInM+=lOmOk4L`O?{i&qxy&D*_qorRbDwj6?)!ef z#JLd7F6Z2I$S0iYI={rZNk*<{HtIl^mx=h>Cim*04K4+Z4IJtd*-)%6XV2(M<qEcY zKpTExU9W`Sp|>CscPiw_a+y*?BKbTS@BZ3AUao^%Zi#PhoY9Vib4N>SE%4>=Jco0v zH_Miey{E;FkdlZSq)e<{`+S3W=*ttvD#hB8w=|2aV*D=yOV}<n%QCtpFj!1iP3=++ zF%bul8RQG~xNUT@7_D%fDp&f9U3+!yV(BF^EJ6M?ggfgy%D_aSJLQh<Q8L9^3Z4lP zSliD?8{L~ZN{}ULe$or4iOcd9fCXx)uXD>(&p%0LbEWH$&@$X3x~CiF-?ejQ*N+-M zc8zT@3iwkdRT2t(XS`d7`tJQAjRmKAhiw{WOqpuvFp`i@Q@!KMhwKgs<K(HF*wpN5 zv(vj1XA8yT@r9sbul0J^6}T8DTrg3?UvaTK(_8@BG(vOS@R#A};jf~t=|7FM{G%;V z$moCx(glgj5-;%1QM|u%2d3FX97|2!-{zNf(~wZQL8&V6ON(xoE>A}%@sw8Xo5Y=F zhRJZg)O4uqNWj?V&&vth*H#je6T}}p_<>!Dr#89q@uSjWv~JuW(>FqoJ5^ho0%K?E z9?x_Q;kmcsQ@5=}z@tdljMSt9-Z3xn$k)kEjK|qXS>EfuDmu(Z8|(W?g<kN}okBu| z`906+8rq=5w?nFA6VC1#eQVZ_=+&soKuCq9J4-B?5ajOsO<ZqBE?J2XT_J8fPV98+ zk#wtSBTro80%$s5KaeCr*oviwvkprv-mw0v@x!YSCMmDCbzwIduaRkq+nkD$>Y6-l z@R_#M8=vxKMAoi&PwnaIYw2COJM@atcgfr=zK1bvjW?9B`-+Voe$Q+H$j!1$Tjn+* z&LY<%)L@;zhnJlB^Og6I<R<r5yYZK!bg%i+z^Gb9&z&*Z#pVBay5jNKYESI$cqK!; zs%j&*N?LE3ILkbKV_0UUpL<A`zeQtv+?k$&h|~*OX&e)^SV^abQ&PMGXtX3fI2kT= z2Y%RbH`bf;|K;F8Mxo)Ov25Y*lHOz#D>&BOR-m?{IW;tyYC%FZ!&Z>kGjHJ6cqM-F z&19n+e1=9AH1VrVeHrIzqlC`w9=*zfmrerF?JMzO&|Mmv;!4DKc(sp+jy^Dx?(8>1 zH&yS_4yL7m&GWX~mdfgH*AB4<e8V;o9`b8>{CKo;+egw=PrvkTaoBU+P-4u?E|&!c z)DKc;>$$B6u*Zr1SjUh<mc1^2+c=@@6(J4|#?}T_|M2b62=4`4F-ba1m43BpL!aCj zR^w2TEDEd$X7pi$++6T@mH_M(zN#-+gi}U5eaDqd^tUG_>2)FeuWLWHl5TH(UHWkf zLs>7px!c5n;rbe^lO@ql<wf#W%s8knI~Th~JR_Kl+2&@Zoorl!op+Ba_ZYj2yD(^E z$}7%1B7{$MlPHueM^5x<Vc5^Pd5$8yYQ@u;!UngDNs9O`zY)-uu_X-;n9-+TuAb`^ z<H1e|G%#k-<p?8qbT%m<kMd#1>YLzlDVp(z?6r<WUtyWnlD^G9B?_Ur{&KCOuHNMq zk|B^K_<0Q-9-+@;d#BY&2k-R$to<44{eG#pW>PZel=YB)Uv&n!2{+Mb$-vQl=xKw( zve&>xYx+jW_NJh!FV||r?;hdP<!CWxpcsZKiv4>*jOXYcLCp>DOtJ?2S^)DkM{{Eb zS$!L$e_o0(^}n3tA1R3-$SNvgBq;DOEo}fNc|tB%%#g4RA3{|euq)p+xd3I8^4E&m zFrD%}nvG^HUAIKe9_{tXB;tl|G<%>yk6R;8L2)KUJw4yHJXUO<O#J#etA!EQr#Ixj zZuFu$GT+Wpqx#)|V^@Cm`sHrRN~=Je%6V#~5_a6U7SazOW-GgiQtB4%%~2(B0iBsg z;PpJsF|+l@`Wy@y_OtfS`JgrB)rNO1MTjsxeQ7|k!FQ^3n6kbM;^~mT&4KxW*m77y zq%{h&JwttX7mQ1|xDfr$rzHoYHzjn|^DmxVimK9<IM)^a;|9O2LO78(*WR_|D40bM z4}thc%eqOsDqUE<D1~O4evp0zw~wzT!F>PM>(-+jxq4R;z8H#>rnJy*)8N+$wA$^F z<U&lTYAkA<S9x1+2s?lu2|Zd2nj#EvZB!v_&9eAD+8*)ghmbT+{)~_^Px6pMeOz2X zv~Wjk&YGtROVvA~E^msuyea-{C!TM*WVVa4lhy%2Gi&UvdDpYWzNapW2o<z2pU37x zeudIr){wxOzdWU}R?Ue;nbpX4`c>N+H*3t)eFEgxLw+Nw3};4WV$qj&_D`%ADV2%r zJCPCo%{=z7;`F98(us5JnT(G@sKTZ^;2FVitXyLe-S5(hV&Ium+1pIUB(CZ#h|g)u zSLJJ<@HgrDiA-}V_6B^x1>c9B6%~847JkQ!^KLZ2skm;q*edo;UA)~?SghG8;QbHh z_6M;ouo_1rq9=x$<`Y@EA{C%6-pEV}B(1#sDoe_e1s3^Y>n#1Sw;N|}8D|s|VPd+g z-_$QhCz`vLxxrVMx3ape1xu3*wjx=yKSlM~nFgkNWb4?DDr*!?U)L_VeffF<+!j|b zZ$Wn2$TDv3C3V@BHpSgv3JUif8%hk%OsGZ=OxH@8&4`bbf$`aAMchl^qN>Eyu3JH} z9-S!x8-s4fE=lad%Pkp8hAs~u?|uRnL48O|;<hL9ZDZTaoVqCgAV4_fXA_B>*DEU! zuS0{cpk%1E0nc__2%;apFsTm0bKtd&A0~S3Cj^?72-*Owk3V!ZG*PswDfS~}2<8le z5+W^`Y(&R)yVF*tU_s!XMcJS`;<i5$MCe|U*GT!0%*LADX`D^%6_<=D#Ru0`TRN8+ zm@tIK)49`32a<@shitOU#x<QU%nW!IzfjK>(Tr`J0%>p=Z&InR%D3@KEzzI+-2)HK zuoNZ&o=wUC&+*?ofPb0a(E6(<2Amd6%uSu_^-<1?hsxs~0K5^f(L<W1_uUGAdyXWF z-9E^}>sGqgEF^+0_H=uNk9S0bb!|O8d?m5gQjUKevPaO+*VfSn^2892K~%crWM8+6 z25@V?Y@J<9w%@NXh-2!}SK_(X)O4AM1-WTg>sj1{lj5@=q&dxE^9xng1_z9w9DK>| z6Iybcd0<ba%T-PM@iR4f+hWNy2(Dh#%r^4ZjOOcYUhl?lcc*@SuVYF<0NRX~sTl15 z&yX+gisvpMdp($7GpQ}~BtfayBnqkt65sVAS)H#))Ya=X_9qRpsELVk)K-Umx|Q>e zy<csGv$iOY<#zt!tLyihB^h0nm-w?)HRS0&_TFyZkN{(*U!r-+J#Pt@VJw|c&+Ad7 zGuhURv<S1E^2YPq{$<>i;Ew!KBRIfGPGytQ6}z}MeXCfLY0?9%RiyagSp_D1?N&c{ zyo>VbJ4Gy`@Fv+5cKgUgs~na$>BV{*em7PU3%lloy_aEovR+J7TfQKh8BJXyL6<F; zULuFu;b(C;CC(l^>|P8un-Jnq(ghd!_HEOh$zlv2$~y3krgeH;9zC}V3<xe_B^^Vb z>f`uDtW(%mT#944DQa~^8ZI+zAUu4U(j0YcDfKR$bK#gvn_{JZ<YX};laf~yTsdEA zA~Ra?VD!R`MyGN9;7}SV*B=q$h>>|gZ5+)u?T$w<UlM8Es^_5l0fa>7Q%F^;!Wk?G z(le7r!ufT*cxS}PR6hIVtXa)i`d$-_1KkyBU>qmgz-=T};uxx&sKgv48akIWQ89F{ z0<y9Cbjk%^#=J+qPnsNw%*mP1XLirQj9jh94t22gxgVWwR*I>XiY?WM^~;|T8zBOr zs#zuOONzH?svv*jokd5SK8wG>+yMC)LYL|vLqm^PMHcT=`}V$=nIRHe2?h)8WQa6O zPAU}d`1y(>kZiP~Gr=mtJLMu`i<2CspL|q2DqAgAD^7*$xzM`PU4^ga`ilE134XBQ z99P(LhHU@7qvl9Yzg$M`+dlS=x^(m-_3t|h>S}E0bcFMn=C|KamQ)=w2^e)35p`zY zRV8X?d;s^>Cof2SPR&nP3E+-LCkS0J$H!eh8~k0qo$}00b=7!H_I2O+Ro@3O$nPdm ztmbOO^B+IHzQ5w>@@@J4cKw5&^_w6s!s=H%&byAbUtczPQ7}wfTqxxtQNfn*u73Qw zGuWsrky_ajPx-5`R<)6xHf>C(oqGf_Fw|-U*GfS?xLML$kv;h_pZ@Kk$y0X(S+K80 z6^|z)*`5VUkawg}=z`S;VhZhxyDfrE0$<offD>(PMurAxl~<>lfZa>JZ288ULK7D` zl9|#L^JL}Y$j*j`0-K6kH#?bRmg#5L3iB4Z)%iF@SqT+Lp|{i`m%R-|ZE94Np7Pa5 zCqC^V3}B(FR340pmF*qaa}M}+h6}mqE~7Sh!9bDv9YRT|>vBNAqv09zXHMlcuhKD| zcjjA(b*XCIwJ33?CB!+;{)vX@9xns_b-VO{i0y?}{!sdXj1GM8+$#v>W7nw;+O_9B z_{4L;C6ol?(?W0<6taGEn1^uG=?Q3i29sE`RfYCaV$3DKc_;?HsL?D_fSYg}SuO5U zOB_f4^vZ_x%o`5|C@9C5+o=mFy@au{s)sKw!UgC&L35aH(sgDxRE2De%(%OT=VUdN ziVLEmdOvJ&5*tCMKRyXctCwQu_RH%;m<lO9)YlolKp~SHA~$RD@rJEPJ4LfFabjtz zzIU?%C*Qz8oJB~DbsOtV|5q`38L}^8Uq{e{^Ki<?YLnvYT2b=9GoWdOL!w)E5Yy?N zCPB}zb-LW~opI;Pm$>*$YK&m;jtbdH#Ak~13T1^f89tn`A%QEHWs~jnY~E}p_Z$XC z=?YXLCkzVSK+Id`xZYTegb@W8_baLt-Fq`Tv|=)JPbFsKRm)4UW;yT+J`<<s6L^~# zDKX^stn#n?Mc#=>)%#ue9DPOkje)YF2fsCilK9MIIK>p*`fkoD5nGfmLwt)!KOT+> zOFq*VZktDDyM3P5UOg`~XL#cbzC}eL%qMB=Q5$d89MKuN<r)TznqqP**!jJ?cnTT2 zaaf?rvaC;><?H&|zm@ni*?D9zRWNdd5|h7<r<^y7j=M<<S|!iYxdgG*6u6u?mWfD3 zB)<Dfkbae`fO#+9WEYybHeZv}*cbdmPDkPU(jb+Sl1(!A;;QmZ9oNWRty}&5QMWy9 zX_w<YIby`Y;2BC{-IfA^=3f)~-*KF*rKr=krZyJeUl;NhG@Ajb2fr2VF0H7ZuP8_; zl#_lD<2+R)LHx3c896sfpWG@kpwT@>#$6|4gx_Jt0Gfn8w&q}%lq4QU%6#jT*MRT% zrLz~C8FYKHawn-EQWN1B75O&quS+Z81(zN)G>~vN8VwC+e+y(`>HcxC{MrJ;H1Z4k zZWuv$w_F0-Ub%MVcpIc){4PGL^I7M{>;hS?;eH!;<Yf7EM>gmcOE66z3;Z1Phqo(t zVP(Hg6q#0gIKgsg7L7WE!{Y#1nI(45tx2{$34dDd#!Z0NIyrm)HOn5W#7;f4pQci# zDW!FI(g4e668kI9{2+mLwB+=#9bfqgX%!B34V-$wwSN(_cm*^{y0jQtv*4}eO^sOV z*9xoNvX)c9isB}Tgx&ZRjp3kwhTVK?r9;n<haxnrRq){mtk9A+#MWR@iL>!x>^XYT z@Q^7zp{rkIs{2mUSE^2!Gf6$6;j~&4=-0cSJJDizZp6LTe8b45;{AKM%v99}{{FfC zz709%u0mC=1KXTo(=TqmZQ;c?$M3z(!xah>aywrj40sc2y3rKFw4jCq+Y+u=CH@_V zxz|qeTwa>+<|H%8Dz5u>ZI5MmjTFwXS-Fv!TDd*`>3{krWoNVx$<133`(ftS?ZPyY z&4@ah^3^i`vL$BZa>O|Nt?ucewzsF)0zX3qmM^|waXr=T0pfIb0*$AwU=?Ipl|1Y; z*Pk6{C-p4MY;j@IJ|DW<V4g+WfmkDAI{!240rBm;^p*C?EK5<-i6<dFN`<4WIVA6x zQ_A}VBKmDESd)f<tKV+_7{`O-ZQ=Kw_N>>QHZQJcp;Z~?8(Q+Kk3^0qJ}SCk^*n4W zu9ZFwLHUx-$6xvaQ)SUQcYd6fF8&x)V`1bIuX@>{mE$b|Yd(qomn3;bPwnDUc0F=; zh*6_((%bqAYQWQ~odER?h>1mkL4kpb3s7`0m@rDKGU*oyF)$j~Ffd4fXV$?`f~rHf z<dmhsigJ=rWi_aV`WXyhB>B%Y)@5SXZvfwm10RY5X?TEo)PK_`L6qgBp=#>fO49$D zDq8Ozj0q6213tV5Qq=;fZ0$|KroY{Dz=l@lU^J)?Ko@ti20TRplXzphBi>XGx4bou zEWrkNjz0t5j!_ke{g5I#PUlEU$Km8g8TE|XK=MkU@PT4T><2OVamoK;wJ}3X0L$vX zgd7gNa359*nc)R-0!`2X@FOTB`+oETOPc=ubp5R)VQgY+5BTZZJ2<L28T@@Z{~(FZ zheu(w_rw1D2_zLx!dpDtOmwLC!DhBIo<Q>?9QwnO=<wr%&Gfr?0?EHFALMv;_+d?S zzAg%@ydS-+C)WJy(gMckj>dnulIUF3gFn;BODC2)65)HeVd%t86sL7Rv^Y+nbn+&l z6BAJY(ETvwI)Ts$aiE8rht4KD*qNyE{8{x6R|%akbTBzw;2+6<pQ&SDXNQj*or8md z6z#{?Yky9DqRtSV0CMnGmM?NZ;=ja)lj3y_HwGOxfijBU4|3qigw`1zRQjL!B8PR+ zaRn%p#eR@M4(R@Wz!rx^(f#sKB!vBtl{_H&pMv^{xCn<;&`rM&o>Echkt+W+`u^XX z_z&x%n<Jwv#rI=O_ITYt8jK&7Lbvimxh?Mpm*TNff4FbaUEWX?w*B~|ab(^T*a99t zcJ#fCD8IP<V1pf_@pm2K2=}<d0_Y2*QClSUBi8yzf&VOuJ`CJAoEUwr?!mKD=5}o2 zV^&)q)<B;SMXmbXj|caU)A+-MMW5C}&8F^$XYi3}kDOaQe6Z+qH3z$S;;<vL9ydXD zI5~P97&YCq9}$m^On$P-pTjcf#j%4IH8Sc*nG=+l4{M+gXHaFf{g{b8PUBySZmJ4r UfUyy3EX0IC28@JalTrWuAK7&_a{vGU literal 0 HcmV?d00001 diff --git a/server/gradle/wrapper/gradle-wrapper.properties b/server/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..a4413138c --- /dev/null +++ b/server/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/server/gradlew b/server/gradlew new file mode 100644 index 000000000..b740cf133 --- /dev/null +++ b/server/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/server/gradlew.bat b/server/gradlew.bat new file mode 100644 index 000000000..25da30dbd --- /dev/null +++ b/server/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/server/settings.gradle b/server/settings.gradle new file mode 100644 index 000000000..dbbee46fb --- /dev/null +++ b/server/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'haengdong' diff --git a/server/src/main/java/server/haengdong/HaengdongApplication.java b/server/src/main/java/server/haengdong/HaengdongApplication.java new file mode 100644 index 000000000..31b6e46e7 --- /dev/null +++ b/server/src/main/java/server/haengdong/HaengdongApplication.java @@ -0,0 +1,13 @@ +package server.haengdong; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class HaengdongApplication { + + public static void main(String[] args) { + SpringApplication.run(HaengdongApplication.class, args); + } + +} diff --git a/server/src/main/java/server/haengdong/application/ActionService.java b/server/src/main/java/server/haengdong/application/ActionService.java new file mode 100644 index 000000000..bda638756 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/ActionService.java @@ -0,0 +1,37 @@ +package server.haengdong.application; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import server.haengdong.application.response.MemberBillReportAppResponse; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.action.MemberBillReport; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Service +public class ActionService { + + private final BillActionRepository billActionRepository; + private final MemberActionRepository memberActionRepository; + private final EventRepository eventRepository; + + public List<MemberBillReportAppResponse> getMemberBillReports(String token) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + List<BillAction> billActions = billActionRepository.findByAction_Event(event); + List<MemberAction> memberActions = memberActionRepository.findAllByEvent(event); + + MemberBillReport memberBillReport = MemberBillReport.createByActions(billActions, memberActions); + + return memberBillReport.getReports().entrySet().stream() + .map(entry -> new MemberBillReportAppResponse(entry.getKey(), entry.getValue())) + .toList(); + } +} diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java new file mode 100644 index 000000000..257d33a3e --- /dev/null +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -0,0 +1,44 @@ +package server.haengdong.application; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.BillActionAppRequest; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.action.ActionRepository; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class BillActionService { + + private final BillActionRepository billActionRepository; + private final ActionRepository actionRepository; + private final EventRepository eventRepository; + + @Transactional + public void saveAllBillAction(String eventToken, List<BillActionAppRequest> requests) { + Event event = eventRepository.findByToken(eventToken) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + Action action = createStartAction(event); + + for (BillActionAppRequest request : requests) { + BillAction billAction = request.toBillAction(action); + billActionRepository.save(billAction); + action = action.next(); + } + } + + private Action createStartAction(Event event) { + return actionRepository.findLastByEvent(event) + .map(Action::next) + .orElse(Action.createFirst(event)); + } +} diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java new file mode 100644 index 000000000..9ad502606 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -0,0 +1,91 @@ +package server.haengdong.application; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.EventAppResponse; +import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.domain.event.EventTokenProvider; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class EventService { + + private final EventRepository eventRepository; + private final EventTokenProvider eventTokenProvider; + private final BillActionRepository billActionRepository; + private final MemberActionRepository memberActionRepository; + + @Transactional + public EventAppResponse saveEvent(EventAppRequest request) { + String token = eventTokenProvider.createToken(); + Event event = request.toEvent(token); + eventRepository.save(event); + + return EventAppResponse.of(event); + } + + public EventDetailAppResponse findEvent(String token) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + + return EventDetailAppResponse.of(event); + } + + public List<ActionAppResponse> findActions(String token) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + + List<BillAction> billActions = billActionRepository.findByAction_Event(event).stream() + .sorted(Comparator.comparing(BillAction::getSequence)).toList(); + List<MemberAction> memberActions = memberActionRepository.findAllByEvent(event).stream() + .sorted(Comparator.comparing(MemberAction::getSequence)).toList(); + + return getActionAppResponses(billActions, memberActions); + } + + private List<ActionAppResponse> getActionAppResponses( + List<BillAction> billActions, + List<MemberAction> memberActions + ) { + int billActionIndex = 0; + int memberActionIndex = 0; + List<ActionAppResponse> actionAppResponses = new ArrayList<>(); + + while (billActionIndex < billActions.size() && memberActionIndex < memberActions.size()) { + BillAction billAction = billActions.get(billActionIndex); + MemberAction memberAction = memberActions.get(memberActionIndex); + if (billAction.getSequence() < memberAction.getSequence()) { + actionAppResponses.add(ActionAppResponse.of(billAction)); + billActionIndex++; + } else { + actionAppResponses.add(ActionAppResponse.of(memberAction)); + memberActionIndex++; + } + } + while (billActionIndex < billActions.size()) { + BillAction billAction = billActions.get(billActionIndex++); + actionAppResponses.add(ActionAppResponse.of(billAction)); + } + while (memberActionIndex < memberActions.size()) { + MemberAction memberAction = memberActions.get(memberActionIndex++); + actionAppResponses.add(ActionAppResponse.of(memberAction)); + } + + return actionAppResponses; + } +} diff --git a/server/src/main/java/server/haengdong/application/MemberActionFactory.java b/server/src/main/java/server/haengdong/application/MemberActionFactory.java new file mode 100644 index 000000000..cbe34f0ef --- /dev/null +++ b/server/src/main/java/server/haengdong/application/MemberActionFactory.java @@ -0,0 +1,82 @@ +package server.haengdong.application; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionStatus; +import server.haengdong.domain.action.MemberGroupIdProvider; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Component +public class MemberActionFactory { + + private final MemberGroupIdProvider memberGroupIdProvider; + + public List<MemberAction> createMemberActions( + MemberActionsSaveAppRequest request, + List<MemberAction> memberActions, + Action action + ) { + validateMemberNames(request); + validateActions(request, memberActions); + + Long memberGroupId = memberGroupIdProvider.createGroupId(); + List<MemberAction> createdMemberActions = new ArrayList<>(); + List<MemberActionSaveAppRequest> actions = request.actions(); + for (MemberActionSaveAppRequest appRequest : actions) { + MemberAction memberAction = appRequest.toMemberAction(action, memberGroupId); + createdMemberActions.add(memberAction); + action = action.next(); + } + + return createdMemberActions; + } + + private void validateMemberNames(MemberActionsSaveAppRequest request) { + List<String> memberNames = request.actions().stream() + .map(MemberActionSaveAppRequest::name) + .toList(); + + long uniqueCount = memberNames.stream().distinct().count(); + if (uniqueCount != memberNames.size()) { + throw new HaengdongException(HaengdongErrorCode.DUPLICATED_MEMBER_ACTION); + } + } + + private void validateActions(MemberActionsSaveAppRequest request, List<MemberAction> memberActions) { + List<MemberAction> reverseSortedMemberActions = memberActions.stream() + .sorted(Comparator.comparing(MemberAction::getSequence).reversed()) + .toList(); + + for (MemberActionSaveAppRequest action : request.actions()) { + validateAction(action, reverseSortedMemberActions); + } + } + + private void validateAction(MemberActionSaveAppRequest request, List<MemberAction> memberActions) { + MemberActionStatus memberActionStatus = MemberActionStatus.of(request.status()); + if (isInvalidStatus(memberActions, request.name(), memberActionStatus)) { + throw new HaengdongException(HaengdongErrorCode.INVALID_MEMBER_ACTION); + } + } + + private boolean isInvalidStatus( + List<MemberAction> memberActions, + String memberName, + MemberActionStatus memberActionStatus + ) { + return memberActions.stream() + .filter(action -> action.isSameName(memberName)) + .findFirst() + .map(action -> action.isSameStatus(memberActionStatus)) + .orElse(MemberActionStatus.IN != memberActionStatus); + } +} diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java new file mode 100644 index 000000000..5094bf2c0 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -0,0 +1,60 @@ +package server.haengdong.application; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.application.response.CurrentMemberAppResponse; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.ActionRepository; +import server.haengdong.domain.action.CurrentMembers; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class MemberActionService { + + private final MemberActionFactory memberActionFactory; + private final MemberActionRepository memberActionRepository; + private final EventRepository eventRepository; + private final ActionRepository actionRepository; + + @Transactional + public void saveMemberAction(String token, MemberActionsSaveAppRequest request) { + Event event = findEvent(token); + + List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event); + Action action = createStartAction(event); + List<MemberAction> memberActions = memberActionFactory.createMemberActions(request, findMemberActions, action); + memberActionRepository.saveAll(memberActions); + } + + private Action createStartAction(Event event) { + return actionRepository.findLastByEvent(event) + .map(Action::next) + .orElse(Action.createFirst(event)); + } + + public List<CurrentMemberAppResponse> getCurrentMembers(String token) { + Event event = findEvent(token); + List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event); + CurrentMembers currentMembers = CurrentMembers.of(findMemberActions); + + return currentMembers.getMembers() + .stream() + .map(CurrentMemberAppResponse::new) + .toList(); + } + + private Event findEvent(String token) { + return eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java new file mode 100644 index 000000000..acd0149f9 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java @@ -0,0 +1,14 @@ +package server.haengdong.application.request; + +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; + +public record BillActionAppRequest( + String title, + Long price +) { + + public BillAction toBillAction(Action action) { + return new BillAction(action, title, price); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/EventAppRequest.java b/server/src/main/java/server/haengdong/application/request/EventAppRequest.java new file mode 100644 index 000000000..1eea6adf4 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/EventAppRequest.java @@ -0,0 +1,10 @@ +package server.haengdong.application.request; + +import server.haengdong.domain.event.Event; + +public record EventAppRequest(String name) { + + public Event toEvent(String token) { + return new Event(name, token); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java new file mode 100644 index 000000000..f7f8d8fc2 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java @@ -0,0 +1,12 @@ +package server.haengdong.application.request; + +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionStatus; + +public record MemberActionSaveAppRequest(String name, String status) { + + public MemberAction toMemberAction(Action action, Long memberGroupId) { + return new MemberAction(action, name, MemberActionStatus.of(status), memberGroupId); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java new file mode 100644 index 000000000..650b908df --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java @@ -0,0 +1,6 @@ +package server.haengdong.application.request; + +import java.util.List; + +public record MemberActionsSaveAppRequest(List<MemberActionSaveAppRequest> actions) { +} diff --git a/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java b/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java new file mode 100644 index 000000000..a1abcc35b --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java @@ -0,0 +1,54 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionStatus; + +public record ActionAppResponse( + Long actionId, + String name, + Long price, + Long sequence, + ActionType actionType +) { + + public static ActionAppResponse of(BillAction billAction) { + return new ActionAppResponse( + billAction.getAction().getId(), + billAction.getTitle(), + billAction.getPrice(), + billAction.getSequence(), + ActionType.BILL + ); + } + + public static ActionAppResponse of(MemberAction memberAction) { + MemberActionStatus status = memberAction.getStatus(); + + return new ActionAppResponse( + memberAction.getAction().getId(), + memberAction.getMemberName(), + null, + memberAction.getSequence(), + ActionType.of(status) + ); + } + + public String actionTypeName() { + return actionType.name(); + } + + public enum ActionType { + BILL, + IN, + OUT, + ; + + private static ActionType of(MemberActionStatus memberActionStatus) { + if (MemberActionStatus.IN == memberActionStatus) { + return IN; + } + return OUT; + } + } +} diff --git a/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java b/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java new file mode 100644 index 000000000..6c682d3e9 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.action.MemberAction; + +public record CurrentMemberAppResponse(String name) { + + public static CurrentMemberAppResponse of(MemberAction memberAction) { + return new CurrentMemberAppResponse(memberAction.getMemberName()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/EventAppResponse.java b/server/src/main/java/server/haengdong/application/response/EventAppResponse.java new file mode 100644 index 000000000..f331d0011 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/EventAppResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.event.Event; + +public record EventAppResponse(String token) { + + public static EventAppResponse of(Event event) { + return new EventAppResponse(event.getToken()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java b/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java new file mode 100644 index 000000000..6e38826d4 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.event.Event; + +public record EventDetailAppResponse(String eventName) { + + public static EventDetailAppResponse of(Event event) { + return new EventDetailAppResponse(event.getName()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java b/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java new file mode 100644 index 000000000..21b6cef56 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java @@ -0,0 +1,4 @@ +package server.haengdong.application.response; + +public record MemberBillReportAppResponse(String name, Long price) { +} diff --git a/server/src/main/java/server/haengdong/config/WebConfig.java b/server/src/main/java/server/haengdong/config/WebConfig.java new file mode 100644 index 000000000..129d8b790 --- /dev/null +++ b/server/src/main/java/server/haengdong/config/WebConfig.java @@ -0,0 +1,27 @@ +package server.haengdong.config; + +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@RequiredArgsConstructor +@Configuration +public class WebConfig implements WebMvcConfigurer { + + @Value("${cors.max-age}") + private Long maxAge; + + @Value("${cors.allowed-origins}") + private String[] allowedOrigins; + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOrigins(allowedOrigins) + .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS") + .allowedHeaders("*") + .maxAge(maxAge); + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/Action.java b/server/src/main/java/server/haengdong/domain/action/Action.java new file mode 100644 index 000000000..11f91fc38 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/Action.java @@ -0,0 +1,42 @@ +package server.haengdong.domain.action; + +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import server.haengdong.domain.event.Event; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class Action { + + private static final long FIRST_SEQUENCE = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + private Event event; + + private Long sequence; + + public Action(Event event, Long sequence) { + this.event = event; + this.sequence = sequence; + } + + public static Action createFirst(Event event) { + return new Action(event, FIRST_SEQUENCE); + } + + public Action next() { + return new Action(event, sequence + 1); + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/ActionRepository.java b/server/src/main/java/server/haengdong/domain/action/ActionRepository.java new file mode 100644 index 000000000..c2138e42f --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/ActionRepository.java @@ -0,0 +1,21 @@ +package server.haengdong.domain.action; + +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.event.Event; + +@Repository +public interface ActionRepository extends JpaRepository<Action, Long> { + + @Query(""" + SELECT a + FROM Action a + WHERE a.event = :event + ORDER BY a.sequence DESC + LIMIT 1 + """) + Optional<Action> findLastByEvent(@Param("event") Event event); +} diff --git a/server/src/main/java/server/haengdong/domain/action/BillAction.java b/server/src/main/java/server/haengdong/domain/action/BillAction.java new file mode 100644 index 000000000..1027206f5 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/BillAction.java @@ -0,0 +1,70 @@ +package server.haengdong.domain.action; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToOne; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class BillAction implements Comparable<BillAction> { + + private static final int MIN_TITLE_LENGTH = 2; + private static final int MAX_TITLE_LENGTH = 30; + private static final long MIN_PRICE = 1L; + private static final long MAX_PRICE = 10_000_000L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) + private Action action; + + @Column(length = MAX_TITLE_LENGTH) + private String title; + + private Long price; + + public BillAction(Action action, String title, Long price) { + validateTitle(title); + validatePrice(price); + this.action = action; + this.title = title.trim(); + this.price = price; + } + + private void validateTitle(String title) { + int titleLength = title.trim().length(); + if (titleLength < MIN_TITLE_LENGTH || titleLength > MAX_TITLE_LENGTH) { + throw new HaengdongException(HaengdongErrorCode.BAD_REQUEST, + String.format("앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다.", MIN_TITLE_LENGTH, MAX_TITLE_LENGTH)); + } + } + + private void validatePrice(Long price) { + if (price < MIN_PRICE || price > MAX_PRICE) { + throw new HaengdongException(HaengdongErrorCode.BAD_REQUEST, + String.format("지출 금액은 %,d 이하의 자연수여야 합니다.", MAX_PRICE)); + } + } + + public Long getSequence() { + return action.getSequence(); + } + + @Override + public int compareTo(BillAction o) { + return Long.compare(this.getSequence(), o.getSequence()); + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java new file mode 100644 index 000000000..1ad7416aa --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java @@ -0,0 +1,14 @@ +package server.haengdong.domain.action; + +import java.util.List; +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.event.Event; + +@Repository +public interface BillActionRepository extends JpaRepository<BillAction, Long> { + + @EntityGraph(attributePaths = {"action"}) + List<BillAction> findByAction_Event(Event event); +} diff --git a/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java b/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java new file mode 100644 index 000000000..298a8a965 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java @@ -0,0 +1,66 @@ +package server.haengdong.domain.action; + +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class CurrentMembers { + + private final Set<String> members; + + public CurrentMembers() { + this(new HashSet<>()); + } + + private CurrentMembers(Set<String> members) { + this.members = members; + } + + public static CurrentMembers of(List<MemberAction> memberActions) { + List<MemberAction> sortedMemberActions = getSortedMemberActions(memberActions); + Set<String> members = new HashSet<>(); + for (MemberAction memberAction : sortedMemberActions) { + String member = memberAction.getMemberName(); + if (memberAction.isSameStatus(MemberActionStatus.IN)) { + members.add(member); + continue; + } + members.remove(member); + } + + return new CurrentMembers(members); + } + + private static List<MemberAction> getSortedMemberActions(List<MemberAction> memberActions) { + return memberActions.stream() + .sorted(Comparator.comparing(MemberAction::getSequence)) + .toList(); + } + + public CurrentMembers addMemberAction(MemberAction memberAction) { + String memberName = memberAction.getMemberName(); + + Set<String> currentMembers = new HashSet<>(members); + + if (memberAction.isIn()) { + currentMembers.add(memberName); + } else { + currentMembers.remove(memberName); + } + return new CurrentMembers(currentMembers); + } + + public boolean isEmpty() { + return members.isEmpty(); + } + + public int size() { + return members.size(); + } + + public Set<String> getMembers() { + return Collections.unmodifiableSet(members); + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberAction.java b/server/src/main/java/server/haengdong/domain/action/MemberAction.java new file mode 100644 index 000000000..67387cbde --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/MemberAction.java @@ -0,0 +1,62 @@ +package server.haengdong.domain.action; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToOne; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class MemberAction implements Comparable<MemberAction> { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) + private Action action; + + private String memberName; + + @Enumerated(EnumType.STRING) + private MemberActionStatus status; + + private Long memberGroupId; + + public MemberAction(Action action, String memberName, MemberActionStatus status, Long memberGroupId) { + this.action = action; + this.memberName = memberName; + this.status = status; + this.memberGroupId = memberGroupId; + } + + public boolean isSameName(String name) { + return memberName.equals(name); + } + + public boolean isIn() { + return status == MemberActionStatus.IN; + } + + public boolean isSameStatus(MemberActionStatus memberActionStatus) { + return status == memberActionStatus; + } + + public Long getSequence() { + return action.getSequence(); + } + + @Override + public int compareTo(MemberAction o) { + return Long.compare(this.getSequence(), o.getSequence()); + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java new file mode 100644 index 000000000..6c4769e61 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java @@ -0,0 +1,15 @@ +package server.haengdong.domain.action; + +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.event.Event; + +@Repository +public interface MemberActionRepository extends JpaRepository<MemberAction, Long> { + + @Query("select m from MemberAction m join fetch m.action where m.action.event = :event") + List<MemberAction> findAllByEvent(@Param("event") Event event); +} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java b/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java new file mode 100644 index 000000000..0a20817fd --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java @@ -0,0 +1,19 @@ +package server.haengdong.domain.action; + +import java.util.Arrays; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +public enum MemberActionStatus { + IN, + OUT, + ; + + public static MemberActionStatus of(String status) { + return Arrays.stream(MemberActionStatus.values()) + .filter(s -> s.name().equals(status)) + .findFirst() + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BAD_REQUEST, + "존재하지 않는 인원 변동 액션입니다.")); + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java b/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java new file mode 100644 index 000000000..dbf2b49ac --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java @@ -0,0 +1,75 @@ +package server.haengdong.domain.action; + +import static java.util.stream.Collectors.toMap; + +import java.util.List; +import java.util.Map; +import java.util.PriorityQueue; +import java.util.function.Function; +import lombok.Getter; + +@Getter +public class MemberBillReport { + + private final Map<String, Long> reports; + + private MemberBillReport(Map<String, Long> reports) { + this.reports = reports; + } + + public static MemberBillReport createByActions(List<BillAction> billActions, List<MemberAction> memberActions) { + PriorityQueue<BillAction> sortedBillActions = new PriorityQueue<>(billActions); + PriorityQueue<MemberAction> sortedMemberActions = new PriorityQueue<>(memberActions); + + Map<String, Long> memberBillReports = initReports(memberActions); + CurrentMembers currentMembers = new CurrentMembers(); + while (!sortedBillActions.isEmpty() && !sortedMemberActions.isEmpty()) { + if (isMemberActionTurn(sortedMemberActions, sortedBillActions)) { + MemberAction memberAction = sortedMemberActions.poll(); + currentMembers = currentMembers.addMemberAction(memberAction); + continue; + } + addBillAction(sortedBillActions, currentMembers, memberBillReports); + } + + while (!sortedBillActions.isEmpty()) { + addBillAction(sortedBillActions, currentMembers, memberBillReports); + } + + return new MemberBillReport(memberBillReports); + } + + private static Map<String, Long> initReports(List<MemberAction> memberActions) { + return memberActions.stream() + .map(MemberAction::getMemberName) + .distinct() + .collect(toMap(Function.identity(), i -> 0L)); + } + + private static boolean isMemberActionTurn( + PriorityQueue<MemberAction> memberActions, + PriorityQueue<BillAction> billActions + ) { + MemberAction memberAction = memberActions.peek(); + BillAction billAction = billActions.peek(); + + return memberAction.getSequence() < billAction.getSequence(); + } + + private static void addBillAction( + PriorityQueue<BillAction> sortedBillActions, + CurrentMembers currentMembers, + Map<String, Long> memberBillReports + ) { + BillAction billAction = sortedBillActions.poll(); + if (currentMembers.isEmpty()) { + return; + } + + Long pricePerMember = billAction.getPrice() / currentMembers.size(); + for (String currentMember : currentMembers.getMembers()) { + Long price = memberBillReports.get(currentMember) + pricePerMember; + memberBillReports.put(currentMember, price); + } + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java b/server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java new file mode 100644 index 000000000..9e32bd733 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java @@ -0,0 +1,11 @@ +package server.haengdong.domain.action; + +import org.springframework.stereotype.Component; + +@Component +public class MemberGroupIdProvider { + + public Long createGroupId() { + return System.currentTimeMillis(); + } +} diff --git a/server/src/main/java/server/haengdong/domain/event/Event.java b/server/src/main/java/server/haengdong/domain/event/Event.java new file mode 100644 index 000000000..24369a184 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/Event.java @@ -0,0 +1,54 @@ +package server.haengdong.domain.event; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class Event { + + private static final int MIN_NAME_LENGTH = 2; + private static final int MAX_NAME_LENGTH = 20; + private static final String SPACES = " "; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String name; + + private String token; + + public Event(String name, String token) { + validateName(name); + this.name = name; + this.token = token; + } + + private void validateName(String name) { + int nameLength = name.length(); + if (nameLength < MIN_NAME_LENGTH || MAX_NAME_LENGTH < nameLength) { + throw new HaengdongException(HaengdongErrorCode.BAD_REQUEST, + String.format("행사 이름은 %d자 이상 %d자 이하만 입력 가능합니다. 입력한 이름 길이 : %d", + MIN_NAME_LENGTH, + MAX_NAME_LENGTH, + name.length())); + } + if (isBlankContinuous(name)) { + throw new HaengdongException(HaengdongErrorCode.BAD_REQUEST, + String.format("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s", name)); + } + } + + private boolean isBlankContinuous(String name) { + return name.contains(SPACES); + } +} diff --git a/server/src/main/java/server/haengdong/domain/event/EventRepository.java b/server/src/main/java/server/haengdong/domain/event/EventRepository.java new file mode 100644 index 000000000..6038c368b --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/EventRepository.java @@ -0,0 +1,11 @@ +package server.haengdong.domain.event; + +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface EventRepository extends JpaRepository<Event, Long> { + + Optional<Event> findByToken(String token); +} diff --git a/server/src/main/java/server/haengdong/domain/event/EventStep.java b/server/src/main/java/server/haengdong/domain/event/EventStep.java new file mode 100644 index 000000000..297abdb66 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/EventStep.java @@ -0,0 +1,28 @@ +package server.haengdong.domain.event; + +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class EventStep { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + private Event event; + + private String name; + + private Long sequence; +} diff --git a/server/src/main/java/server/haengdong/domain/event/EventTokenProvider.java b/server/src/main/java/server/haengdong/domain/event/EventTokenProvider.java new file mode 100644 index 000000000..6450f0dcf --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/EventTokenProvider.java @@ -0,0 +1,12 @@ +package server.haengdong.domain.event; + +import java.util.UUID; +import org.springframework.stereotype.Component; + +@Component +public class EventTokenProvider { + + public String createToken() { + return UUID.randomUUID().toString(); + } +} diff --git a/server/src/main/java/server/haengdong/exception/ErrorResponse.java b/server/src/main/java/server/haengdong/exception/ErrorResponse.java new file mode 100644 index 000000000..c797b811a --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/ErrorResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.exception; + +public record ErrorResponse( + String message +) { + + public static ErrorResponse of(String message) { + return new ErrorResponse(message); + } +} diff --git a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java new file mode 100644 index 000000000..bb3138cc7 --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java @@ -0,0 +1,43 @@ +package server.haengdong.exception; + +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@Slf4j +@RestControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + public ResponseEntity<ErrorResponse> haengdongException() { + return ResponseEntity.badRequest() + .body(ErrorResponse.of(HaengdongErrorCode.BAD_REQUEST.getMessage())); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity<ErrorResponse> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { + String errorMessage = e.getFieldErrors().stream() + .map(error -> error.getField() + " " + error.getDefaultMessage()) + .collect(Collectors.joining(", ")); + + return ResponseEntity.badRequest() + .body(ErrorResponse.of(errorMessage)); + } + + @ExceptionHandler(HaengdongException.class) + public ResponseEntity<ErrorResponse> haengdongException(HaengdongException e) { + return ResponseEntity.status(e.getStatusCode()) + .body(ErrorResponse.of(e.getMessage())); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity<ErrorResponse> handleException(Exception e) { + log.error(e.getMessage(), e); + return ResponseEntity.internalServerError() + .body(ErrorResponse.of(HaengdongErrorCode.INTERNAL_SERVER_ERROR.getMessage())); + } +} diff --git a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java new file mode 100644 index 000000000..792baa838 --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java @@ -0,0 +1,24 @@ +package server.haengdong.exception; + +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +public enum HaengdongErrorCode { + BAD_REQUEST(HttpStatus.BAD_REQUEST, "잘못된 요청입니다."), + DUPLICATED_MEMBER_ACTION(HttpStatus.BAD_REQUEST, "올바르지 않은 인원 요청입니다."), + INVALID_MEMBER_ACTION(HttpStatus.BAD_REQUEST, "잘못된 맴버 액션입니다."), + + NOT_FOUND_EVENT(HttpStatus.NOT_FOUND, "존재하지 않는 행사입니다."), + + INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버 내부에서 에러가 발생했습니다."), + ; + + private final HttpStatus httpStatus; + private final String message; + + HaengdongErrorCode(HttpStatus httpStatus, String message) { + this.httpStatus = httpStatus; + this.message = message; + } +} diff --git a/server/src/main/java/server/haengdong/exception/HaengdongException.java b/server/src/main/java/server/haengdong/exception/HaengdongException.java new file mode 100644 index 000000000..812df50f8 --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/HaengdongException.java @@ -0,0 +1,32 @@ +package server.haengdong.exception; + +import lombok.Getter; +import org.springframework.http.HttpStatusCode; + +@Getter +public class HaengdongException extends RuntimeException { + + private final HaengdongErrorCode errorCode; + private final String message; + + public HaengdongException(HaengdongErrorCode errorCode) { + this(errorCode, null); + } + + public HaengdongException(HaengdongErrorCode errorCode, String message) { + this.errorCode = errorCode; + this.message = message; + } + + public HttpStatusCode getStatusCode() { + return errorCode.getHttpStatus(); + } + + @Override + public String getMessage() { + if (message == null) { + return errorCode.getMessage(); + } + return message; + } +} diff --git a/server/src/main/java/server/haengdong/presentation/ActionController.java b/server/src/main/java/server/haengdong/presentation/ActionController.java new file mode 100644 index 000000000..657cb567e --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/ActionController.java @@ -0,0 +1,26 @@ +package server.haengdong.presentation; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.ActionService; +import server.haengdong.application.response.MemberBillReportAppResponse; +import server.haengdong.presentation.response.MemberBillReportsResponse; + +@RequiredArgsConstructor +@RestController +public class ActionController { + + private final ActionService actionService; + + @GetMapping("/api/events/{eventId}/actions/reports") + public ResponseEntity<MemberBillReportsResponse> getMemberBillReports(@PathVariable("eventId") String token) { + List<MemberBillReportAppResponse> memberBillReports = actionService.getMemberBillReports(token); + + return ResponseEntity.ok() + .body(MemberBillReportsResponse.of(memberBillReports)); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/BillActionController.java b/server/src/main/java/server/haengdong/presentation/BillActionController.java new file mode 100644 index 000000000..fcdacb270 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/BillActionController.java @@ -0,0 +1,29 @@ +package server.haengdong.presentation; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.BillActionService; +import server.haengdong.presentation.request.BillActionsSaveRequest; + +@RequiredArgsConstructor +@RestController +public class BillActionController { + + private final BillActionService billActionService; + + @PostMapping("/api/events/{eventId}/actions/bills") + public ResponseEntity<Void> saveAllBillAction( + @PathVariable("eventId") String token, + @RequestBody @Valid BillActionsSaveRequest request + ) { + billActionService.saveAllBillAction(token, request.toAppRequests()); + + return ResponseEntity.ok() + .build(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java new file mode 100644 index 000000000..9fbe098ce --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -0,0 +1,43 @@ +package server.haengdong.presentation; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.EventService; +import server.haengdong.presentation.request.EventSaveRequest; +import server.haengdong.presentation.response.EventDetailResponse; +import server.haengdong.presentation.response.EventResponse; +import server.haengdong.presentation.response.StepResponse; + +@RequiredArgsConstructor +@RestController +public class EventController { + + private final EventService eventService; + + @PostMapping("/api/events") + public ResponseEntity<EventResponse> saveEvent(@Valid @RequestBody EventSaveRequest request) { + EventResponse eventResponse = EventResponse.of(eventService.saveEvent(request.toAppRequest())); + + return ResponseEntity.ok(eventResponse); + } + + @GetMapping("/api/events/{eventId}") + public ResponseEntity<EventDetailResponse> findEvent(@PathVariable("eventId") String token) { + EventDetailResponse eventDetailResponse = EventDetailResponse.of(eventService.findEvent(token)); + + return ResponseEntity.ok(eventDetailResponse); + } + + @GetMapping("/api/events/{eventId}/actions") + public ResponseEntity<StepResponse> findActions(@PathVariable("eventId") String token) { + StepResponse stepResponse = StepResponse.of(eventService.findActions(token)); + + return ResponseEntity.ok(stepResponse); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/MemberActionController.java b/server/src/main/java/server/haengdong/presentation/MemberActionController.java new file mode 100644 index 000000000..c12370d86 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/MemberActionController.java @@ -0,0 +1,39 @@ +package server.haengdong.presentation; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.MemberActionService; +import server.haengdong.application.response.CurrentMemberAppResponse; +import server.haengdong.presentation.request.MemberActionsSaveRequest; +import server.haengdong.presentation.response.CurrentMembersResponse; + +@RequiredArgsConstructor +@RestController +public class MemberActionController { + + private final MemberActionService memberActionService; + + @PostMapping("/api/events/{eventId}/actions/members") + public ResponseEntity<Void> saveMemberAction( + @PathVariable("eventId") String token, + @RequestBody MemberActionsSaveRequest request + ) { + memberActionService.saveMemberAction(token, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } + + @GetMapping("/api/events/{eventId}/members/current") + public ResponseEntity<CurrentMembersResponse> getCurrentMembers(@PathVariable("eventId") String token) { + List<CurrentMemberAppResponse> currentMembers = memberActionService.getCurrentMembers(token); + + return ResponseEntity.ok() + .body(CurrentMembersResponse.of(currentMembers)); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java new file mode 100644 index 000000000..a0d878f7f --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java @@ -0,0 +1,19 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import server.haengdong.application.request.BillActionAppRequest; + +public record BillActionSaveRequest( + + @NotBlank + String title, + + @NotNull + Long price +) { + + public BillActionAppRequest toAppRequest() { + return new BillActionAppRequest(title, price); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java new file mode 100644 index 000000000..68784039b --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java @@ -0,0 +1,14 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.Valid; +import java.util.List; +import server.haengdong.application.request.BillActionAppRequest; + +public record BillActionsSaveRequest(@Valid List<BillActionSaveRequest> actions) { + + public List<BillActionAppRequest> toAppRequests() { + return actions.stream() + .map(BillActionSaveRequest::toAppRequest) + .toList(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java new file mode 100644 index 000000000..b28572332 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java @@ -0,0 +1,15 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import server.haengdong.application.request.EventAppRequest; + +public record EventSaveRequest( + + @NotBlank + String eventName +) { + + public EventAppRequest toAppRequest() { + return new EventAppRequest(eventName); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java new file mode 100644 index 000000000..0b3fcebae --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java @@ -0,0 +1,22 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import java.util.List; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; + +public record MemberActionsSaveRequest( + List<String> members, + + @NotBlank + String status +) { + + public MemberActionsSaveAppRequest toAppRequest() { + List<MemberActionSaveAppRequest> appRequests = members.stream() + .map(name -> new MemberActionSaveAppRequest(name, status)) + .toList(); + + return new MemberActionsSaveAppRequest(appRequests); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java b/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java new file mode 100644 index 000000000..a58e60186 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java @@ -0,0 +1,20 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.ActionAppResponse; + +public record ActionResponse( + Long actionId, + String name, + Long price, + Long sequence +) { + + public static ActionResponse of(ActionAppResponse actionAppResponse) { + return new ActionResponse( + actionAppResponse.actionId(), + actionAppResponse.name(), + actionAppResponse.price(), + actionAppResponse.sequence() + ); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java b/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java new file mode 100644 index 000000000..188c48dc9 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java @@ -0,0 +1,28 @@ +package server.haengdong.presentation.response; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import server.haengdong.application.response.ActionAppResponse; + +public record ActionsResponse( + String type, + String stepName, + Set<String> members, + List<ActionResponse> actions +) { + + public static ActionsResponse of(List<ActionAppResponse> actions, Set<String> members) { + List<ActionResponse> actionResponses = actions.stream() + .map(ActionResponse::of) + .toList(); + + String actionType = actions.get(0).actionTypeName(); + return new ActionsResponse( + actionType, + null, + new HashSet<>(members), + actionResponses + ); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/CurrentMemberResponse.java b/server/src/main/java/server/haengdong/presentation/response/CurrentMemberResponse.java new file mode 100644 index 000000000..4308c7d17 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/CurrentMemberResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.CurrentMemberAppResponse; + +public record CurrentMemberResponse(String name) { + + public static CurrentMemberResponse of(CurrentMemberAppResponse response) { + return new CurrentMemberResponse(response.name()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java b/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java new file mode 100644 index 000000000..4eb915dd4 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java @@ -0,0 +1,15 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import server.haengdong.application.response.CurrentMemberAppResponse; + +public record CurrentMembersResponse(List<CurrentMemberResponse> members) { + + public static CurrentMembersResponse of(List<CurrentMemberAppResponse> currentMembers) { + List<CurrentMemberResponse> responses = currentMembers.stream() + .map(CurrentMemberResponse::of) + .toList(); + + return new CurrentMembersResponse(responses); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java b/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java new file mode 100644 index 000000000..c18694393 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.EventDetailAppResponse; + +public record EventDetailResponse(String eventName) { + + public static EventDetailResponse of(EventDetailAppResponse response) { + return new EventDetailResponse(response.eventName()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/EventResponse.java b/server/src/main/java/server/haengdong/presentation/response/EventResponse.java new file mode 100644 index 000000000..506f5e814 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/EventResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.EventAppResponse; + +public record EventResponse(String eventId) { + + public static EventResponse of(EventAppResponse eventAppResponse) { + return new EventResponse(eventAppResponse.token()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java new file mode 100644 index 000000000..0ea409202 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.MemberBillReportAppResponse; + +public record MemberBillReportResponse(String name, Long price) { + + public static MemberBillReportResponse of(MemberBillReportAppResponse memberBillReportAppResponse) { + return new MemberBillReportResponse(memberBillReportAppResponse.name(), memberBillReportAppResponse.price()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java new file mode 100644 index 000000000..d350c4009 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java @@ -0,0 +1,15 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import server.haengdong.application.response.MemberBillReportAppResponse; + +public record MemberBillReportsResponse(List<MemberBillReportResponse> reports) { + + public static MemberBillReportsResponse of(List<MemberBillReportAppResponse> memberBillReports) { + List<MemberBillReportResponse> reports = memberBillReports.stream() + .map(MemberBillReportResponse::of) + .toList(); + + return new MemberBillReportsResponse(reports); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/StepResponse.java b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java new file mode 100644 index 000000000..a8f3877ef --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java @@ -0,0 +1,57 @@ +package server.haengdong.presentation.response; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import server.haengdong.application.response.ActionAppResponse; + +public record StepResponse( + List<ActionsResponse> steps +) { + + public static StepResponse of(List<ActionAppResponse> actions) { + if (actions.isEmpty()) { + return new StepResponse(List.of()); + } + List<ActionsResponse> actionsResponse = new ArrayList<>(); + Set<String> members = new HashSet<>(); + ActionAppResponse firstAction = getFirstAction(actions); + List<ActionAppResponse> group = new ArrayList<>(); + group.add(firstAction); + String currentActionType = firstAction.actionTypeName(); + members.add(firstAction.name()); + + for (int i = 1; i < actions.size(); i++) { + ActionAppResponse action = actions.get(i); + String typeName = action.actionTypeName(); + if (currentActionType.equals(typeName)) { + if (typeName.equals("IN")) { + members.add(action.name()); + } + if (typeName.equals("OUT")) { + members.remove(action.name()); + } + group.add(action); + continue; + } + actionsResponse.add(ActionsResponse.of(group, members)); + currentActionType = typeName; + group.clear(); + if (typeName.equals("IN")) { + members.add(action.name()); + } + if (typeName.equals("OUT")) { + members.remove(action.name()); + } + group.add(action); + } + actionsResponse.add(ActionsResponse.of(group, members)); + + return new StepResponse(actionsResponse); + } + + private static ActionAppResponse getFirstAction(List<ActionAppResponse> actions) { + return actions.get(0); + } +} diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml new file mode 100644 index 000000000..faf7a36f1 --- /dev/null +++ b/server/src/main/resources/application.yml @@ -0,0 +1,31 @@ +spring: + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:mem:database + username: sa + password: + + h2: + console: + enabled: true + path: /h2-console + + jpa: + hibernate: + ddl-auto: create + properties: + hibernate: + format_sql: true + show-sql: true + +cors: + max-age: 3600 + allowed-origins: http://localhost:3000, https://haengdong.pro, https://dev.haengdong.pro, https://app.haengdong.pro + +--- + +spring: + config: + import: classpath:config/application-dev.yml + activate: + on-profile: dev diff --git a/server/src/test/java/server/haengdong/application/ActionServiceTest.java b/server/src/test/java/server/haengdong/application/ActionServiceTest.java new file mode 100644 index 000000000..ac2dc4f4f --- /dev/null +++ b/server/src/test/java/server/haengdong/application/ActionServiceTest.java @@ -0,0 +1,79 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import server.haengdong.application.response.MemberBillReportAppResponse; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@SpringBootTest +class ActionServiceTest { + + @Autowired + private ActionService actionService; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillActionRepository billActionRepository; + + @Autowired + private MemberActionRepository memberActionRepository; + + @DisplayName("참여자별 정산 현황을 조회한다.") + @Test + void getMemberBillReports() { + String token = "tOkEn1"; + Event event = new Event("행동대장", token); + Event savedEvent = eventRepository.save(event); + List<MemberAction> memberActions = List.of( + new MemberAction(new Action(savedEvent, 1L), "소하", IN, 1L), + new MemberAction(new Action(savedEvent, 2L), "감자", IN, 1L), + new MemberAction(new Action(savedEvent, 3L), "쿠키", IN, 1L), + new MemberAction(new Action(savedEvent, 5L), "감자", OUT, 2L) + ); + List<BillAction> billActions = List.of( + new BillAction(new Action(savedEvent, 4L), "뽕족", 60_000L), + new BillAction(new Action(savedEvent, 6L), "인생맥주", 40_000L), + new BillAction(new Action(savedEvent, 7L), "인생네컷", 20_000L) + ); + memberActionRepository.saveAll(memberActions); + billActionRepository.saveAll(billActions); + + List<MemberBillReportAppResponse> responses = actionService.getMemberBillReports(token); + + assertThat(responses) + .hasSize(3) + .extracting(MemberBillReportAppResponse::name, MemberBillReportAppResponse::price) + .containsExactlyInAnyOrder( + tuple("감자", 20_000L), + tuple("쿠키", 50_000L), + tuple("소하", 50_000L) + ); + } + + @DisplayName("존재하지 않는 이벤트의 참여자별 정산 현황을 조회하는 경우 예외가 발생한다.") + @Test + void getMemberBillReports1() { + assertThatThrownBy(() -> actionService.getMemberBillReports("invalid token")) + .isInstanceOf(HaengdongException.class) + .hasMessage(HaengdongErrorCode.NOT_FOUND_EVENT.getMessage()); + } +} diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java new file mode 100644 index 000000000..195d4bdd9 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java @@ -0,0 +1,65 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import server.haengdong.application.request.BillActionAppRequest; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongException; + +@SpringBootTest +class BillActionServiceTest { + + @Autowired + private BillActionService billActionService; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillActionRepository billActionRepository; + + @DisplayName("지출 내역을 생성한다.") + @Test + void saveAllBillAction() { + String token = "TOKEN"; + Event event = new Event("감자", token); + Event savedEvent = eventRepository.save(event); + + List<BillActionAppRequest> requests = List.of( + new BillActionAppRequest("뽕족", 10_000L), + new BillActionAppRequest("인생맥주", 15_000L) + ); + + billActionService.saveAllBillAction(token, requests); + + List<BillAction> actions = billActionRepository.findByAction_Event(savedEvent); + + assertThat(actions).extracting(BillAction::getTitle, BillAction::getPrice, BillAction::getSequence) + .containsExactlyInAnyOrder( + tuple("뽕족", 10_000L, 1L), + tuple("인생맥주", 15_000L, 2L) + ); + } + + @DisplayName("이벤트가 존재하지 않으면 지출 내역을 생성할 수 없다.") + @Test + void saveAllBillAction1() { + List<BillActionAppRequest> requests = List.of( + new BillActionAppRequest("뽕족", 10_000L), + new BillActionAppRequest("인생맥주", 15_000L) + ); + + assertThatThrownBy(() -> billActionService.saveAllBillAction("token", requests)) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/application/EventServiceTest.java b/server/src/test/java/server/haengdong/application/EventServiceTest.java new file mode 100644 index 000000000..5a3e8bce3 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/EventServiceTest.java @@ -0,0 +1,110 @@ +package server.haengdong.application; + + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; +import static org.mockito.BDDMockito.given; + +import java.util.List; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.EventAppResponse; +import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.ActionRepository; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.action.MemberActionStatus; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.domain.event.EventTokenProvider; + +@SpringBootTest +class EventServiceTest { + + @Autowired + private EventService eventService; + + @MockBean + private EventTokenProvider eventTokenProvider; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private ActionRepository actionRepository; + + @Autowired + private BillActionRepository billActionRepository; + + @Autowired + private MemberActionRepository memberActionRepository; + + @AfterEach + void tearDown() { + billActionRepository.deleteAllInBatch(); + memberActionRepository.deleteAllInBatch(); + actionRepository.deleteAllInBatch(); + eventRepository.deleteAllInBatch(); + } + + @DisplayName("행사를 생성한다") + @Test + void saveEventTest() { + EventAppRequest request = new EventAppRequest("test"); + given(eventTokenProvider.createToken()).willReturn("TOKEN"); + + EventAppResponse response = eventService.saveEvent(request); + + assertThat(response.token()).isEqualTo("TOKEN"); + } + + @DisplayName("토큰으로 행사를 조회한다.") + @Test + void findEventTest() { + String token = "TOKEN"; + Event event = new Event("행동대장 회식", token); + eventRepository.save(event); + + EventDetailAppResponse eventDetailAppResponse = eventService.findEvent(token); + + assertThat(eventDetailAppResponse.eventName()).isEqualTo("행동대장 회식"); + } + + @DisplayName("행사에 속한 모든 액션을 조회한다.") + @Test + void findActionsTest() { + Event event = new Event("행동대장 회식", "웨디_토큰"); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + Action action1 = new Action(event, 2L); + MemberAction memberAction1 = new MemberAction(action1, "쿠키", MemberActionStatus.IN, 1L); + Action action2 = new Action(event, 3L); + BillAction billAction = new BillAction(action2, "뽕나무쟁이족발", 30000L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of(memberAction, memberAction1)); + billActionRepository.save(billAction); + + List<ActionAppResponse> actionAppResponses = eventService.findActions("웨디_토큰"); + + assertThat(actionAppResponses).hasSize(3) + .extracting(ActionAppResponse::actionId, + ActionAppResponse::name, + ActionAppResponse::price, + ActionAppResponse::sequence, + ActionAppResponse::actionTypeName) + .containsExactly( + tuple(1L, "토다리", null, 1L, "IN"), + tuple(2L, "쿠키", null, 2L, "IN"), + tuple(3L, "뽕나무쟁이족발", 30000L, 3L, "BILL") + ); + } +} diff --git a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java new file mode 100644 index 000000000..40bee2ff6 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java @@ -0,0 +1,217 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; + +import java.util.List; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionStatus; +import server.haengdong.domain.action.ActionRepository; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.exception.HaengdongException; + +@SpringBootTest +class MemberActionFactoryTest { + + @Autowired + private MemberActionFactory memberActionFactory; + + @Autowired + private MemberActionRepository memberActionRepository; + + @Autowired + private ActionRepository actionRepository; + + @Autowired + private EventRepository eventRepository; + + @AfterEach + void tearDown() { + memberActionRepository.deleteAllInBatch(); + actionRepository.deleteAllInBatch(); + eventRepository.deleteAllInBatch(); + } + + @DisplayName("이전 멤버 액션이 시퀀스 기준으로 정렬되지 않은 상태에서 새로운 멤버 액션 요청을 검증한다.") + @Test + void createMemberActionsTest() { + Event event = eventRepository.save(new Event("우당탕탕 행동대장 백엔드 회식", "토다리_토큰")); + Action action1 = new Action(event, 1L); + Action action2 = new Action(event, 2L); + MemberAction memberAction1 = new MemberAction(action1, "토다리", MemberActionStatus.IN, 1L); + MemberAction memberAction2 = new MemberAction(action2, "토다리", MemberActionStatus.OUT, 2L); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); + List<MemberAction> unorderedMemberActions = List.of(memberAction2, memberAction1); + Action startAction = new Action(event, 3L); + + assertThatThrownBy(() -> memberActionFactory.createMemberActions(request, unorderedMemberActions, startAction)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("인원 변동 액션을 생성한다.") + @Test + void createMemberActionsTest1() { + Event event = eventRepository.save(new Event("우당탕탕 행동대장 백엔드 회식", "토다리_토큰")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest memberActionsSaveAppRequest = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); + Action startAction = new Action(event, 2L); + + List<MemberAction> memberActions = memberActionFactory.createMemberActions(memberActionsSaveAppRequest, + List.of(memberAction), startAction); + + assertThat(memberActions).hasSize(1) + .extracting(MemberAction::getAction, MemberAction::getMemberName, MemberAction::getStatus) + .containsExactly( + tuple(startAction, "토다리", MemberActionStatus.OUT) + ); + } + + @DisplayName("현재 행사에 참여 중인 경우에 퇴장할 수 있다.") + @Test + void createMemberActionsTest2() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에서 퇴장한 경우에 입장할 수 있다.") + @Test + void createMemberActionsTest3() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action1 = new Action(event, 1L); + MemberAction memberAction1 = new MemberAction(action1, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction1); + Action action2 = new Action(event, 2L); + MemberAction memberAction2 = new MemberAction(action2, "토다리", MemberActionStatus.OUT, 2L); + memberActionRepository.save(memberAction2); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "IN"))); + Action startAction = new Action(event, 3L); + + assertThatCode( + () -> memberActionFactory.createMemberActions(request, List.of(memberAction1, memberAction2), + startAction)) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에 입장한 적 없는 경우에 입장할 수 있다.") + @Test + void createMemberActionsTest4() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다.") + @Test + void createMemberActionTest5() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "OUT"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(), startAction)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("행사에 이미 참여 중인 경우 다시 입장할 수 없다.") + @Test + void createMemberActionTest6() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("한 명의 사용자는 동시에 여러 번 입장할 수 없다.") + @Test + void createMemberActionTest7() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "IN"), + new MemberActionSaveAppRequest("쿠키", "IN"))); + Action startAction = new Action(event, 1L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(), startAction)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("한 명의 사용자는 동시에 여러 번 퇴장할 수 없다.") + @Test + void createMemberActionTest8() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "OUT"), + new MemberActionSaveAppRequest("쿠키", "OUT"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("한 명의 사용자는 입장과 퇴장을 동시에 할 수 없다.") + @Test + void createMemberActionTest9() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "IN"), + new MemberActionSaveAppRequest("쿠키", "OUT"))); + Action startAction = new Action(event, 2L); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java new file mode 100644 index 000000000..7212e300d --- /dev/null +++ b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java @@ -0,0 +1,92 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; + +import java.util.List; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.ActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongException; + +@SpringBootTest +class MemberActionServiceTest { + + @Autowired + private MemberActionService memberActionService; + + @Autowired + private MemberActionRepository memberActionRepository; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private ActionRepository actionRepository; + + @AfterEach + void tearDown() { + memberActionRepository.deleteAllInBatch(); + actionRepository.deleteAllInBatch(); + eventRepository.deleteAllInBatch(); + } + + @DisplayName("현재 행사에 참여하고 있는 경우에 나갈 수 있다.") + @Test + void saveMemberActionTest() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "망쵸", IN, 1L); + memberActionRepository.save(memberAction); + + assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("망쵸", "OUT"))))) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에서 퇴장한 경우에 입장할 수 있다.") + @Test + void saveMemberActionTest1() { + Event event = eventRepository.save(new Event("test", "TOKEN")); + Action actionOne = new Action(event, 1L); + MemberAction memberActionOne = new MemberAction(actionOne, "망쵸", IN, 1L); + memberActionRepository.save(memberActionOne); + + Action actionTwo = new Action(event, 2L); + MemberAction memberActionTwo = new MemberAction(actionTwo, "망쵸", OUT, 1L); + memberActionRepository.save(memberActionTwo); + + assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("망쵸", "IN"))))) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다.") + @Test + void saveMemberActionTest2() { + MemberActionsSaveAppRequest appRequest = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("TOKEN", "OUT"))); + + assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", appRequest)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("이벤트가 없으면 현재 참여 인원을 조회할 수 없다.") + @Test + void getCurrentMembers() { + assertThatThrownBy(() -> memberActionService.getCurrentMembers("token")) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/domain/action/ActionTest.java b/server/src/test/java/server/haengdong/domain/action/ActionTest.java new file mode 100644 index 000000000..199a4f628 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/action/ActionTest.java @@ -0,0 +1,30 @@ +package server.haengdong.domain.action; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.domain.event.Event; + +class ActionTest { + + @DisplayName("액션의 초기 순서번호는 1이다.") + @Test + void createFirst() { + Event event = new Event("name", "token"); + Action action = Action.createFirst(event); + + assertThat(action.getSequence()).isOne(); + } + + @DisplayName("현재 액션의 다음 액션의 순서는 1만큼 증가한다.") + @Test + void next() { + Event event = new Event("name", "token"); + Action action = new Action(event, 2L); + + Action nextAction = action.next(); + + assertThat(nextAction.getSequence()).isEqualTo(3L); + } +} diff --git a/server/src/test/java/server/haengdong/domain/action/BillActionTest.java b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java new file mode 100644 index 000000000..601ca95d7 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java @@ -0,0 +1,58 @@ +package server.haengdong.domain.action; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import server.haengdong.domain.event.Event; +import server.haengdong.exception.HaengdongException; + +class BillActionTest { + + @DisplayName("지출 내역 제목의 앞뒤 공백을 제거한 길이가 2 ~ 30자가 아니면 지출을 생성할 수 없다.") + @ParameterizedTest + @ValueSource(strings = {" 감 ", "", " ", "1234567890123456789012345678901"}) + void validateTitle(String title) { + Event event = new Event("name", "token"); + Action action = new Action(event, 1L); + Long price = 100L; + + assertThatThrownBy(() -> new BillAction(action, title, price)) + .isInstanceOf(HaengdongException.class) + .hasMessage("앞뒤 공백을 제거한 지출 내역 제목은 2 ~ 30자여야 합니다."); + } + + @DisplayName("금액이 10,000,000 이하의 자연수가 아니면 지출을 생성할 수 없다.") + @ParameterizedTest + @ValueSource(longs = {0, 10_000_001, 20_000_000}) + void validatePrice(long price) { + Event event = new Event("name", "token"); + Action action = new Action(event, 1L); + String title = "title"; + + assertThatThrownBy(() -> new BillAction(action, title, price)) + .isInstanceOf(HaengdongException.class) + .hasMessage("지출 금액은 10,000,000 이하의 자연수여야 합니다."); + } + + @DisplayName("지출 내역을 올바르게 생성한다.") + @Test + void createBillAction() { + Event event = new Event("name", "token"); + Action action = new Action(event, 1L); + String title = "title"; + Long price = 1_000L; + + BillAction billAction = new BillAction(action, title, price); + + assertAll( + () -> assertThat(billAction.getAction()).isEqualTo(action), + () -> assertThat(billAction.getTitle()).isEqualTo(title), + () -> assertThat(billAction.getPrice()).isEqualTo(price) + ); + } +} diff --git a/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java b/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java new file mode 100644 index 000000000..389ca70c1 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java @@ -0,0 +1,58 @@ +package server.haengdong.domain.action; + +import static org.assertj.core.api.Assertions.assertThat; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; + +import java.util.List; +import java.util.Set; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.domain.event.Event; + +class CurrentMembersTest { + + @DisplayName("인원 변동 이력으로 현재 참여 인원을 계산한다.") + @Test + void of() { + Event event = new Event("test", "TOKEN"); + List<MemberAction> memberActions = List.of( + new MemberAction(new Action(event, 1L), "망쵸", IN, 1L), + new MemberAction(new Action(event, 2L), "백호", IN, 1L), + new MemberAction(new Action(event, 3L), "백호", OUT, 1L), + new MemberAction(new Action(event, 4L), "웨디", IN, 1L) + ); + + CurrentMembers currentMembers = CurrentMembers.of(memberActions); + + assertThat(currentMembers.getMembers()) + .containsExactlyInAnyOrder("망쵸", "웨디"); + } + + @DisplayName("인원 변동 액션의 상태가 IN이면 현재 인원에 추가한다.") + @Test + void addMemberAction1() { + CurrentMembers currentMembers = new CurrentMembers(); + Event event = new Event("이벤트", "token"); + MemberAction memberAction = new MemberAction(new Action(event, 1L), "웨디", IN, 1L); + + CurrentMembers addedCurrentMembers = currentMembers.addMemberAction(memberAction); + Set<String> members = addedCurrentMembers.getMembers(); + + assertThat(members).hasSize(1) + .containsExactly("웨디"); + } + + @DisplayName("인원 변동 액션의 상태가 OUT이면 현재 인원에서 제외한다.") + @Test + void addMemberAction2() { + Event event = new Event("이벤트", "token"); + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "웨디", IN, 1L); + CurrentMembers currentMembers = new CurrentMembers().addMemberAction(memberAction1); + MemberAction memberAction2 = new MemberAction(new Action(event, 1L), "웨디", OUT, 1L); + + CurrentMembers addedCurrentMembers = currentMembers.addMemberAction(memberAction2); + + assertThat(addedCurrentMembers.getMembers()).hasSize(0); + } +} diff --git a/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java b/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java new file mode 100644 index 000000000..9ad27d5bc --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java @@ -0,0 +1,43 @@ +package server.haengdong.domain.action; + +import static org.assertj.core.api.Assertions.assertThat; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; + +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.domain.event.Event; + +class MemberBillReportTest { + + @DisplayName("액션 목록으로 참가자 정산 리포트를 생성한다.") + @Test + void createByActions() { + String token = "TOK2N"; + Event event = new Event("행동대장", token); + List<BillAction> billActions = List.of( + new BillAction(new Action(event, 4L), "뽕족", 60_000L), + new BillAction(new Action(event, 6L), "인생맥주", 40_000L), + new BillAction(new Action(event, 7L), "인생네컷", 20_000L) + ); + List<MemberAction> memberActions = List.of( + new MemberAction(new Action(event, 1L), "소하", IN, 1L), + new MemberAction(new Action(event, 2L), "감자", IN, 1L), + new MemberAction(new Action(event, 3L), "쿠키", IN, 1L), + new MemberAction(new Action(event, 5L), "감자", OUT, 2L) + ); + + MemberBillReport memberBillReport = MemberBillReport.createByActions(billActions, memberActions); + + assertThat(memberBillReport.getReports()) + .containsAllEntriesOf( + Map.of( + "감자", 20_000L, + "쿠키", 50_000L, + "소하", 50_000L + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/domain/event/EventTest.java b/server/src/test/java/server/haengdong/domain/event/EventTest.java new file mode 100644 index 000000000..98f6c7050 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/event/EventTest.java @@ -0,0 +1,37 @@ +package server.haengdong.domain.event; + +import static org.assertj.core.api.Assertions.assertThatCode; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import server.haengdong.exception.HaengdongException; + +class EventTest { + + @DisplayName("공백 문자가 연속되지 않고, 이름이 2자 이상 20자 이하인 행사를 생성하면 예외가 발생하지 않는다.") + @ParameterizedTest + @ValueSource(strings = {"12", "12345678901234567890", "공 백", " 공백", "공백 ", " 공 백 "}) + void createSuccessTest(String eventName) { + assertThatCode(() -> new Event(eventName, "TEST_TOKEN")) + .doesNotThrowAnyException(); + } + + @DisplayName("공백 문자가 연속되면 예외가 발생한다.") + @ParameterizedTest + @ValueSource(strings = {" 공백", "공백 ", "공백 연속", "공 백"}) + void createFailTest1(String eventName) { + assertThatCode(() -> new Event(eventName, "TEST_TOKEN")) + .isInstanceOf(HaengdongException.class) + .hasMessage(String.format("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s", eventName)); + } + + @DisplayName("이름이 2자 미만이거나 20자 초과인 경우 예외가 발생한다.") + @ParameterizedTest + @ValueSource(strings = {"", " ", "123456789012345678901"}) + void createFilTest2(String eventName) { + assertThatCode(() -> new Event(eventName, "TEST_TOKEN")) + .isInstanceOf(HaengdongException.class) + .hasMessage(String.format("행사 이름은 2자 이상 20자 이하만 입력 가능합니다. 입력한 이름 길이 : %d", eventName.length())); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java new file mode 100644 index 000000000..739ac4962 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java @@ -0,0 +1,49 @@ +package server.haengdong.presentation; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import server.haengdong.application.ActionService; +import server.haengdong.application.response.MemberBillReportAppResponse; + +@WebMvcTest(ActionController.class) +class ActionControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private ActionService actionService; + + @DisplayName("참여자별 정산 현황을 조회한다.") + @Test + void getMemberBillReports() throws Exception { + List<MemberBillReportAppResponse> memberBillReportAppResponses = List.of( + new MemberBillReportAppResponse("소하", 20_000L), new MemberBillReportAppResponse("토다리", 200_000L)); + + given(actionService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); + + mockMvc.perform(get("/api/events/{token}/actions/reports", "token") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].name").value(equalTo("소하"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].price").value(equalTo(20_000))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].name").value(equalTo("토다리"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].price").value(equalTo(200_000))); + + } +} diff --git a/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java new file mode 100644 index 000000000..8bf2b292f --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java @@ -0,0 +1,69 @@ +package server.haengdong.presentation; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import server.haengdong.application.BillActionService; +import server.haengdong.presentation.request.BillActionSaveRequest; +import server.haengdong.presentation.request.BillActionsSaveRequest; + +@WebMvcTest(BillActionController.class) +class BillActionControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private BillActionService billActionService; + + @DisplayName("지출 내역을 생성한다.") + @Test + void saveAllBillAction() throws Exception { + BillActionsSaveRequest request = new BillActionsSaveRequest( + List.of( + new BillActionSaveRequest("뽕족", 10_000L), + new BillActionSaveRequest("인생맥주", 10_000L) + ) + ); + String requestBody = objectMapper.writeValueAsString(request); + String token = "TOKEN"; + + mockMvc.perform(post("/api/events/{token}/actions/bills", token) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("title이 비어 있는 경우 지출 내역을 생성할 수 없다.") + @Test + void saveAllBillAction1() throws Exception { + BillActionsSaveRequest request = new BillActionsSaveRequest( + List.of( + new BillActionSaveRequest("", 10_000L), + new BillActionSaveRequest("인생맥주", 10_000L) + ) + ); + String requestBody = objectMapper.writeValueAsString(request); + String token = "TOKEN"; + + mockMvc.perform(post("/api/events/{token}/actions/bills", token) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isBadRequest()); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java new file mode 100644 index 000000000..55a48630f --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java @@ -0,0 +1,66 @@ +package server.haengdong.presentation; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import server.haengdong.application.EventService; +import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.response.EventAppResponse; +import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.presentation.request.EventSaveRequest; + +@WebMvcTest(EventController.class) +class EventControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private EventService eventService; + + @DisplayName("이벤트를 생성한다.") + @Test + void saveEvent() throws Exception { + EventSaveRequest eventSaveRequest = new EventSaveRequest("토다리"); + String requestBody = objectMapper.writeValueAsString(eventSaveRequest); + String token = "TOKEN"; + EventAppResponse eventAppResponse = new EventAppResponse(token); + given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); + + mockMvc.perform(post("/api/events") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.eventId").value("TOKEN")); + } + + @DisplayName("토큰으로 행사를 조회한다.") + @Test + void findEventTest() throws Exception { + String token = "TOKEN"; + EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식"); + given(eventService.findEvent(token)).willReturn(eventDetailAppResponse); + + mockMvc.perform(get("/api/events/" + token)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.eventName").value("행동대장 회식")); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java new file mode 100644 index 000000000..ad8787cc6 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java @@ -0,0 +1,67 @@ +package server.haengdong.presentation; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import server.haengdong.application.MemberActionService; +import server.haengdong.application.response.CurrentMemberAppResponse; +import server.haengdong.presentation.request.MemberActionsSaveRequest; + +@WebMvcTest(MemberActionController.class) +class MemberActionControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private MemberActionService memberActionService; + + @DisplayName("참여자 행동을 추가한다.") + @Test + void saveMemberActionTest() throws Exception { + MemberActionsSaveRequest memberActionsSaveRequest = new MemberActionsSaveRequest( + List.of("웨디", "소하", "토다리", "쿠키"), "IN"); + + String requestBody = objectMapper.writeValueAsString(memberActionsSaveRequest); + + mockMvc.perform(post("/api/events/TOKEN/actions/members") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("현재 참여 인원을 조회합니다.") + @Test + void getCurrentMembers() throws Exception { + List<CurrentMemberAppResponse> currentMemberAppResponses = List.of( + new CurrentMemberAppResponse("소하"), new CurrentMemberAppResponse("토다리")); + + given(memberActionService.getCurrentMembers(any())).willReturn(currentMemberAppResponses); + + mockMvc.perform(get("/api/events/{token}/members/current", "token") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.members[0].name").value(equalTo("소하"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.members[1].name").value(equalTo("토다리"))); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/response/StepResponseTest.java b/server/src/test/java/server/haengdong/presentation/response/StepResponseTest.java new file mode 100644 index 000000000..aac78691c --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/response/StepResponseTest.java @@ -0,0 +1,57 @@ +package server.haengdong.presentation.response; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.ActionAppResponse.ActionType; + +@SpringBootTest +class StepResponseTest { + + @Autowired + private ObjectMapper objectMapper; + + @DisplayName("") + @Test + void test() throws JsonProcessingException { + List<ActionAppResponse> actionAppResponse = new ArrayList<>(); + + // IN actions + ActionAppResponse actionAppResponse1 = new ActionAppResponse(3L, "망쵸", null, 3L, ActionType.IN); + actionAppResponse.add(actionAppResponse1); + ActionAppResponse actionAppResponse2 = new ActionAppResponse(4L, "백호", null, 4L, ActionType.IN); + actionAppResponse.add(actionAppResponse2); + + // BILL step 1 + ActionAppResponse actionAppResponse3 = new ActionAppResponse(1L, "감자탕", 10000L, 1L, ActionType.BILL); + actionAppResponse.add(actionAppResponse3); + ActionAppResponse actionAppResponse4 = new ActionAppResponse(2L, "인생네컷", 10000L, 2L, ActionType.BILL); + actionAppResponse.add(actionAppResponse4); + + // IN actions + ActionAppResponse actionAppResponse5 = new ActionAppResponse(5L, "소하", null, 5L, ActionType.IN); + actionAppResponse.add(actionAppResponse5); + ActionAppResponse actionAppResponse6 = new ActionAppResponse(6L, "웨디", null, 6L, ActionType.IN); + actionAppResponse.add(actionAppResponse6); + + // OUT actions + ActionAppResponse actionAppResponse7 = new ActionAppResponse(7L, "망쵸", null, 7L, ActionType.OUT); + actionAppResponse.add(actionAppResponse7); + ActionAppResponse actionAppResponse8 = new ActionAppResponse(8L, "백호", null, 8L, ActionType.OUT); + actionAppResponse.add(actionAppResponse8); + + // BILL step 2 + ActionAppResponse actionAppResponse9 = new ActionAppResponse(9L, "노래방", 20000L, 10L, ActionType.BILL); + actionAppResponse.add(actionAppResponse9); + + // StepResponse creation + StepResponse stepResponse = StepResponse.of(actionAppResponse); + System.out.println("stepResponse = " + stepResponse); + } +} diff --git a/server/src/test/resources/application.yml b/server/src/test/resources/application.yml new file mode 100644 index 000000000..2d02b2712 --- /dev/null +++ b/server/src/test/resources/application.yml @@ -0,0 +1,18 @@ +spring: + h2: + console: + enabled: true + path: /h2-console + datasource: + url: jdbc:h2:mem:database + jpa: + defer-datasource-initialization: true + show-sql: true + properties: + hibernate: + format_sql: true + hibernate: + ddl-auto: create-drop +cors: + max-age: 3600 + allowed-origins: http://localhost:8080 From 4675795da3fe82e347bf6cd5832dcfc9af49634c Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Mon, 29 Jul 2024 19:27:20 +0900 Subject: [PATCH 104/178] =?UTF-8?q?fix:=20gradlew=20=EA=B6=8C=ED=95=9C=20?= =?UTF-8?q?=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95=20(#152)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/backend-pull-request.yml | 3 +++ .github/workflows/backend-push.yml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/backend-pull-request.yml b/.github/workflows/backend-pull-request.yml index 113972929..6ede1b600 100644 --- a/.github/workflows/backend-pull-request.yml +++ b/.github/workflows/backend-pull-request.yml @@ -27,6 +27,9 @@ jobs: - name: Setup Gradle uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Test with Gradle Wrapper run: ./gradlew clean build diff --git a/.github/workflows/backend-push.yml b/.github/workflows/backend-push.yml index d385a69c8..c9c2316c8 100644 --- a/.github/workflows/backend-push.yml +++ b/.github/workflows/backend-push.yml @@ -34,6 +34,9 @@ jobs: - name: Setup Gradle uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Test with Gradle Wrapper run: ./gradlew clean build From 568ffc70550946aac6e4b029cb0aa280ef886d30 Mon Sep 17 00:00:00 2001 From: 3juhwan <13selfesteem91@naver.com> Date: Tue, 30 Jul 2024 11:17:44 +0900 Subject: [PATCH 105/178] =?UTF-8?q?remove:=20=ED=81=B4=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EC=96=B8=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/design-pull-request.yml | 61 - .github/workflows/frontend-pull-request.yml | 34 - HDesign/.gitignore | 12 - HDesign/.npmignore | 7 - HDesign/.npmrc | 2 - HDesign/.prettierrc | 12 - HDesign/.storybook/main.ts | 46 - HDesign/.storybook/preview.tsx | 41 - HDesign/eslint.config.mjs | 151 - HDesign/package-lock.json | 13638 ---------------- HDesign/package.json | 69 - HDesign/src/assets/arrow.svg | 3 - HDesign/src/assets/buljusa.svg | 4 - HDesign/src/assets/index.ts | 4 - HDesign/src/assets/inputDelete.svg | 4 - HDesign/src/assets/plus.svg | 4 - HDesign/src/assets/svg.d.ts | 6 - .../components/BillItem/BillItem.stories.tsx | 32 - .../src/components/BillItem/BillItem.style.ts | 8 - HDesign/src/components/BillItem/BillItem.tsx | 34 - .../src/components/BillItem/BillItem.type.ts | 11 - .../BottomSheet/BottomSheet.stories.tsx | 49 - .../BottomSheet/BottomSheet.style.ts | 40 - .../components/BottomSheet/BottomSheet.tsx | 39 - .../BottomSheet/BottomSheet.type.ts | 22 - .../components/BottomSheet/useBottomSheet.ts | 52 - .../src/components/Button/Button.stories.tsx | 40 - HDesign/src/components/Button/Button.style.ts | 72 - HDesign/src/components/Button/Button.tsx | 18 - HDesign/src/components/Button/Button.type.ts | 16 - .../DragHandleItem/DragHandleItem.stories.tsx | 31 - .../DragHandleItem/DragHandleItem.style.ts | 19 - .../DragHandleItem/DragHandleItem.tsx | 38 - .../ExpenseList/ExpenseList.stories.tsx | 29 - .../ExpenseList/ExpenseList.style.ts | 34 - .../components/ExpenseList/ExpenseList.tsx | 45 - .../ExpenseList/ExpenseList.type.ts | 10 - .../FixedButton/FixedButton.stories.tsx | 40 - .../FixedButton/FixedButton.style.ts | 60 - .../components/FixedButton/FixedButton.tsx | 21 - .../FixedButton/FixedButton.type.ts | 14 - HDesign/src/components/Flex/Flex.style.ts | 45 - HDesign/src/components/Flex/Flex.tsx | 16 - HDesign/src/components/Flex/Flex.type.ts | 19 - .../IconButton/IconButton.stories.tsx | 28 - .../src/components/IconButton/IconButton.tsx | 24 - .../components/IconButton/IconButton.type.ts | 11 - .../InOutItem/InOutItem.stories.tsx | 32 - .../components/InOutItem/InOutItem.style.ts | 24 - .../src/components/InOutItem/InOutItem.tsx | 37 - .../components/InOutItem/InOutItem.type.ts | 13 - .../src/components/Input/Input.stories.tsx | 32 - HDesign/src/components/Input/Input.style.ts | 42 - HDesign/src/components/Input/Input.tsx | 30 - HDesign/src/components/Input/Input.type.ts | 15 - HDesign/src/components/Input/useInput.ts | 36 - .../src/components/Search/Search.stories.tsx | 37 - HDesign/src/components/Search/Search.style.ts | 40 - HDesign/src/components/Search/Search.tsx | 44 - HDesign/src/components/Search/useSearch.ts | 39 - .../components/StepItem/StepItem.stories.tsx | 46 - .../src/components/StepItem/StepItem.style.ts | 34 - HDesign/src/components/StepItem/StepItem.tsx | 43 - .../src/components/StepItem/StepItem.type.ts | 13 - .../src/components/Switch/Switch.stories.tsx | 35 - HDesign/src/components/Switch/Switch.style.ts | 6 - HDesign/src/components/Switch/Switch.tsx | 24 - HDesign/src/components/Switch/Switch.type.ts | 5 - HDesign/src/components/Tabs/Tab.tsx | 8 - HDesign/src/components/Tabs/Tab.type.ts | 16 - HDesign/src/components/Tabs/Tabs.stories.tsx | 31 - HDesign/src/components/Tabs/Tabs.style.ts | 51 - HDesign/src/components/Tabs/Tabs.tsx | 53 - HDesign/src/components/Text/Text.stories.tsx | 40 - HDesign/src/components/Text/Text.style.ts | 23 - HDesign/src/components/Text/Text.tsx | 16 - HDesign/src/components/Text/Text.type.ts | 21 - .../TextButton/TextButton.stories.tsx | 50 - .../components/TextButton/TextButton.style.ts | 15 - .../src/components/TextButton/TextButton.tsx | 26 - .../components/TextButton/TextButton.type.ts | 15 - .../src/components/Title/Title.stories.tsx | 37 - HDesign/src/components/Title/Title.style.ts | 39 - HDesign/src/components/Title/Title.tsx | 39 - HDesign/src/components/Title/Title.type.ts | 11 - HDesign/src/components/TopNav/Back.tsx | 17 - .../src/components/TopNav/TopNav.stories.tsx | 50 - HDesign/src/components/TopNav/TopNav.style.ts | 14 - HDesign/src/components/TopNav/TopNav.tsx | 20 - HDesign/src/index.tsx | 51 - HDesign/src/layouts/ContentLayout.tsx | 25 - HDesign/src/layouts/MainLayout.tsx | 25 - HDesign/src/theme/GlobalStyle.ts | 119 - HDesign/src/theme/HDesignProvider.tsx | 37 - HDesign/src/theme/theme.type.ts | 7 - HDesign/src/token/colors.ts | 60 - HDesign/src/token/typography.ts | 67 - HDesign/src/types/strictPropsWithChildren.ts | 3 - .../changeCamelCaseToKebabCase.ts | 3 - HDesign/tsconfig.json | 31 - client/.gitignore | 11 - client/.npmrc | 2 - client/.prettierrc | 12 - client/eslint.config.mjs | 107 - client/index.html | 12 - client/package-lock.json | 11135 ------------- client/package.json | 59 - client/src/App.tsx | 12 - client/src/apis/baseUrl.ts | 3 - client/src/apis/fetcher.ts | 136 - client/src/apis/request/bill.ts | 18 - client/src/apis/request/event.ts | 29 - client/src/apis/request/member.ts | 24 - client/src/apis/request/report.ts | 17 - client/src/apis/request/stepList.ts | 15 - client/src/apis/requestPostEvent.ts | 13 - client/src/apis/tempPrefix.ts | 2 - client/src/apis/withEventId.type.ts | 3 - .../MemberReportList/MemberReportList.tsx | 22 - client/src/components/Modal/Modal.style.ts | 23 - .../SetActionModalContent.style.ts | 16 - .../SetActionModalContent.tsx | 50 - .../SetPurchase.style.ts | 23 - .../SetActionModalContent/SetPurchase.tsx | 60 - .../UpdateParticipants.style.ts | 18 - .../UpdateParticipants.tsx | 49 - .../Modal/SetActionModalContent/index.ts | 1 - .../SetInitialParticipants.style.ts | 20 - .../SetInitialParticipants.tsx | 51 - .../Modal/SetInitialParticipants/index.ts | 1 - client/src/components/Modal/index.ts | 2 - client/src/components/StepList/StepList.tsx | 30 - client/src/constants/routerUrls.ts | 8 - .../src/hooks/useDynamicAdditionalInput.tsx | 52 - client/src/hooks/useDynamicInputPairs.tsx | 45 - client/src/hooks/useEventId/useEventId.tsx | 25 - client/src/hooks/useNavSwitch.tsx | 37 - .../useSearchMemberReportList.tsx | 41 - client/src/hooks/useStepList/type.ts | 38 - client/src/hooks/useStepList/useStepList.tsx | 102 - client/src/index.css | 20 - client/src/index.tsx | 13 - client/src/mocks/memberReportSearchList.json | 10 - client/src/mocks/stepList.json | 86 - client/src/pages/Create/Complete.tsx | 38 - client/src/pages/Create/Name.tsx | 46 - client/src/pages/Create/index.ts | 2 - client/src/pages/Event/Admin/Admin.style.ts | 10 - client/src/pages/Event/Admin/Admin.tsx | 97 - client/src/pages/Event/Admin/index.ts | 1 - client/src/pages/Event/EventLayout.tsx | 23 - client/src/pages/Event/Home/Home.tsx | 40 - client/src/pages/Event/Home/index.ts | 1 - client/src/pages/Event/index.ts | 1 - client/src/pages/Main/Main.tsx | 20 - client/src/pages/Main/index.ts | 1 - client/src/reset.css | 136 - client/src/router.tsx | 44 - client/src/type.d.ts | 18 - client/tsconfig.json | 51 - client/webpack.config.js | 75 - 161 files changed, 29719 deletions(-) delete mode 100644 .github/workflows/design-pull-request.yml delete mode 100644 .github/workflows/frontend-pull-request.yml delete mode 100644 HDesign/.gitignore delete mode 100644 HDesign/.npmignore delete mode 100644 HDesign/.npmrc delete mode 100644 HDesign/.prettierrc delete mode 100644 HDesign/.storybook/main.ts delete mode 100644 HDesign/.storybook/preview.tsx delete mode 100644 HDesign/eslint.config.mjs delete mode 100644 HDesign/package-lock.json delete mode 100644 HDesign/package.json delete mode 100644 HDesign/src/assets/arrow.svg delete mode 100644 HDesign/src/assets/buljusa.svg delete mode 100644 HDesign/src/assets/index.ts delete mode 100644 HDesign/src/assets/inputDelete.svg delete mode 100644 HDesign/src/assets/plus.svg delete mode 100644 HDesign/src/assets/svg.d.ts delete mode 100644 HDesign/src/components/BillItem/BillItem.stories.tsx delete mode 100644 HDesign/src/components/BillItem/BillItem.style.ts delete mode 100644 HDesign/src/components/BillItem/BillItem.tsx delete mode 100644 HDesign/src/components/BillItem/BillItem.type.ts delete mode 100644 HDesign/src/components/BottomSheet/BottomSheet.stories.tsx delete mode 100644 HDesign/src/components/BottomSheet/BottomSheet.style.ts delete mode 100644 HDesign/src/components/BottomSheet/BottomSheet.tsx delete mode 100644 HDesign/src/components/BottomSheet/BottomSheet.type.ts delete mode 100644 HDesign/src/components/BottomSheet/useBottomSheet.ts delete mode 100644 HDesign/src/components/Button/Button.stories.tsx delete mode 100644 HDesign/src/components/Button/Button.style.ts delete mode 100644 HDesign/src/components/Button/Button.tsx delete mode 100644 HDesign/src/components/Button/Button.type.ts delete mode 100644 HDesign/src/components/DragHandleItem/DragHandleItem.stories.tsx delete mode 100644 HDesign/src/components/DragHandleItem/DragHandleItem.style.ts delete mode 100644 HDesign/src/components/DragHandleItem/DragHandleItem.tsx delete mode 100644 HDesign/src/components/ExpenseList/ExpenseList.stories.tsx delete mode 100644 HDesign/src/components/ExpenseList/ExpenseList.style.ts delete mode 100644 HDesign/src/components/ExpenseList/ExpenseList.tsx delete mode 100644 HDesign/src/components/ExpenseList/ExpenseList.type.ts delete mode 100644 HDesign/src/components/FixedButton/FixedButton.stories.tsx delete mode 100644 HDesign/src/components/FixedButton/FixedButton.style.ts delete mode 100644 HDesign/src/components/FixedButton/FixedButton.tsx delete mode 100644 HDesign/src/components/FixedButton/FixedButton.type.ts delete mode 100644 HDesign/src/components/Flex/Flex.style.ts delete mode 100644 HDesign/src/components/Flex/Flex.tsx delete mode 100644 HDesign/src/components/Flex/Flex.type.ts delete mode 100644 HDesign/src/components/IconButton/IconButton.stories.tsx delete mode 100644 HDesign/src/components/IconButton/IconButton.tsx delete mode 100644 HDesign/src/components/IconButton/IconButton.type.ts delete mode 100644 HDesign/src/components/InOutItem/InOutItem.stories.tsx delete mode 100644 HDesign/src/components/InOutItem/InOutItem.style.ts delete mode 100644 HDesign/src/components/InOutItem/InOutItem.tsx delete mode 100644 HDesign/src/components/InOutItem/InOutItem.type.ts delete mode 100644 HDesign/src/components/Input/Input.stories.tsx delete mode 100644 HDesign/src/components/Input/Input.style.ts delete mode 100644 HDesign/src/components/Input/Input.tsx delete mode 100644 HDesign/src/components/Input/Input.type.ts delete mode 100644 HDesign/src/components/Input/useInput.ts delete mode 100644 HDesign/src/components/Search/Search.stories.tsx delete mode 100644 HDesign/src/components/Search/Search.style.ts delete mode 100644 HDesign/src/components/Search/Search.tsx delete mode 100644 HDesign/src/components/Search/useSearch.ts delete mode 100644 HDesign/src/components/StepItem/StepItem.stories.tsx delete mode 100644 HDesign/src/components/StepItem/StepItem.style.ts delete mode 100644 HDesign/src/components/StepItem/StepItem.tsx delete mode 100644 HDesign/src/components/StepItem/StepItem.type.ts delete mode 100644 HDesign/src/components/Switch/Switch.stories.tsx delete mode 100644 HDesign/src/components/Switch/Switch.style.ts delete mode 100644 HDesign/src/components/Switch/Switch.tsx delete mode 100644 HDesign/src/components/Switch/Switch.type.ts delete mode 100644 HDesign/src/components/Tabs/Tab.tsx delete mode 100644 HDesign/src/components/Tabs/Tab.type.ts delete mode 100644 HDesign/src/components/Tabs/Tabs.stories.tsx delete mode 100644 HDesign/src/components/Tabs/Tabs.style.ts delete mode 100644 HDesign/src/components/Tabs/Tabs.tsx delete mode 100644 HDesign/src/components/Text/Text.stories.tsx delete mode 100644 HDesign/src/components/Text/Text.style.ts delete mode 100644 HDesign/src/components/Text/Text.tsx delete mode 100644 HDesign/src/components/Text/Text.type.ts delete mode 100644 HDesign/src/components/TextButton/TextButton.stories.tsx delete mode 100644 HDesign/src/components/TextButton/TextButton.style.ts delete mode 100644 HDesign/src/components/TextButton/TextButton.tsx delete mode 100644 HDesign/src/components/TextButton/TextButton.type.ts delete mode 100644 HDesign/src/components/Title/Title.stories.tsx delete mode 100644 HDesign/src/components/Title/Title.style.ts delete mode 100644 HDesign/src/components/Title/Title.tsx delete mode 100644 HDesign/src/components/Title/Title.type.ts delete mode 100644 HDesign/src/components/TopNav/Back.tsx delete mode 100644 HDesign/src/components/TopNav/TopNav.stories.tsx delete mode 100644 HDesign/src/components/TopNav/TopNav.style.ts delete mode 100644 HDesign/src/components/TopNav/TopNav.tsx delete mode 100644 HDesign/src/index.tsx delete mode 100644 HDesign/src/layouts/ContentLayout.tsx delete mode 100644 HDesign/src/layouts/MainLayout.tsx delete mode 100644 HDesign/src/theme/GlobalStyle.ts delete mode 100644 HDesign/src/theme/HDesignProvider.tsx delete mode 100644 HDesign/src/theme/theme.type.ts delete mode 100644 HDesign/src/token/colors.ts delete mode 100644 HDesign/src/token/typography.ts delete mode 100644 HDesign/src/types/strictPropsWithChildren.ts delete mode 100644 HDesign/src/utils/ return str.replace(/([a-z])([A-Z])/changeCamelCaseToKebabCase.ts delete mode 100644 HDesign/tsconfig.json delete mode 100644 client/.gitignore delete mode 100644 client/.npmrc delete mode 100644 client/.prettierrc delete mode 100644 client/eslint.config.mjs delete mode 100644 client/index.html delete mode 100644 client/package-lock.json delete mode 100644 client/package.json delete mode 100644 client/src/App.tsx delete mode 100644 client/src/apis/baseUrl.ts delete mode 100644 client/src/apis/fetcher.ts delete mode 100644 client/src/apis/request/bill.ts delete mode 100644 client/src/apis/request/event.ts delete mode 100644 client/src/apis/request/member.ts delete mode 100644 client/src/apis/request/report.ts delete mode 100644 client/src/apis/request/stepList.ts delete mode 100644 client/src/apis/requestPostEvent.ts delete mode 100644 client/src/apis/tempPrefix.ts delete mode 100644 client/src/apis/withEventId.type.ts delete mode 100644 client/src/components/MemberReportList/MemberReportList.tsx delete mode 100644 client/src/components/Modal/Modal.style.ts delete mode 100644 client/src/components/Modal/SetActionModalContent/SetActionModalContent.style.ts delete mode 100644 client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx delete mode 100644 client/src/components/Modal/SetActionModalContent/SetPurchase.style.ts delete mode 100644 client/src/components/Modal/SetActionModalContent/SetPurchase.tsx delete mode 100644 client/src/components/Modal/SetActionModalContent/UpdateParticipants.style.ts delete mode 100644 client/src/components/Modal/SetActionModalContent/UpdateParticipants.tsx delete mode 100644 client/src/components/Modal/SetActionModalContent/index.ts delete mode 100644 client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.style.ts delete mode 100644 client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.tsx delete mode 100644 client/src/components/Modal/SetInitialParticipants/index.ts delete mode 100644 client/src/components/Modal/index.ts delete mode 100644 client/src/components/StepList/StepList.tsx delete mode 100644 client/src/constants/routerUrls.ts delete mode 100644 client/src/hooks/useDynamicAdditionalInput.tsx delete mode 100644 client/src/hooks/useDynamicInputPairs.tsx delete mode 100644 client/src/hooks/useEventId/useEventId.tsx delete mode 100644 client/src/hooks/useNavSwitch.tsx delete mode 100644 client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.tsx delete mode 100644 client/src/hooks/useStepList/type.ts delete mode 100644 client/src/hooks/useStepList/useStepList.tsx delete mode 100644 client/src/index.css delete mode 100644 client/src/index.tsx delete mode 100644 client/src/mocks/memberReportSearchList.json delete mode 100644 client/src/mocks/stepList.json delete mode 100644 client/src/pages/Create/Complete.tsx delete mode 100644 client/src/pages/Create/Name.tsx delete mode 100644 client/src/pages/Create/index.ts delete mode 100644 client/src/pages/Event/Admin/Admin.style.ts delete mode 100644 client/src/pages/Event/Admin/Admin.tsx delete mode 100644 client/src/pages/Event/Admin/index.ts delete mode 100644 client/src/pages/Event/EventLayout.tsx delete mode 100644 client/src/pages/Event/Home/Home.tsx delete mode 100644 client/src/pages/Event/Home/index.ts delete mode 100644 client/src/pages/Event/index.ts delete mode 100644 client/src/pages/Main/Main.tsx delete mode 100644 client/src/pages/Main/index.ts delete mode 100644 client/src/reset.css delete mode 100644 client/src/router.tsx delete mode 100644 client/src/type.d.ts delete mode 100644 client/tsconfig.json delete mode 100644 client/webpack.config.js diff --git a/.github/workflows/design-pull-request.yml b/.github/workflows/design-pull-request.yml deleted file mode 100644 index 4d54e8b39..000000000 --- a/.github/workflows/design-pull-request.yml +++ /dev/null @@ -1,61 +0,0 @@ -name: Storybook Deployment -run-name: ${{ github.actor }}의 스토리북 배포 -on: - pull_request: - branches: - - develop - paths: - - 'HDesign/**' - -jobs: - storybook: - runs-on: ubuntu-latest - outputs: - status: ${{ job.status }} - - defaults: - run: - shell: bash - working-directory: ./HDesign - - steps: - - name: checkout repository - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: cache dependencies - id: cache - uses: actions/cache@v3 - with: - path: "**/node_modules" - key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}-storybook - - - name: Set up Node.js - uses: actions/setup-node@v2 - with: - node-version: '20.15.1' - - - name: depedency install - if: steps.cache.outputs.cache-hit != 'true' - run: npm ci - - - name: run lint - working-directory: ./HDesign - run: npm run lint - - - name: publish to chromatic - working-directory: ./HDesign - id: chromatic - uses: chromaui/action@v1 - with: - projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} - token: ${{ secrets.GITHUB_TOKEN }} - - - name: comment PR - uses: thollander/actions-comment-pull-request@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - message: "🚀storybook: ${{ steps.chromatic.outputs.storybookUrl }}" - \ No newline at end of file diff --git a/.github/workflows/frontend-pull-request.yml b/.github/workflows/frontend-pull-request.yml deleted file mode 100644 index b94c4ceeb..000000000 --- a/.github/workflows/frontend-pull-request.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: frontend-pull-request - -on: - pull_request: - types: [opened, synchronize] - branches: [main, develop] - paths: - - 'client/**' - -jobs: - test: - runs-on: ubuntu-latest - - defaults: - run: - shell: bash - working-directory: ./client - - steps: - - name: Checkout code - uses: actions/checkout@v2 - - - name: Set up Node.js - uses: actions/setup-node@v2 - with: - node-version: '20.15.1' - - - name: Install dependencies - working-directory: ./client - run: npm install - - - name: Run lint - working-directory: ./client - run: npm run lint diff --git a/HDesign/.gitignore b/HDesign/.gitignore deleted file mode 100644 index b98928456..000000000 --- a/HDesign/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -logs -*.log -npm-debug.log* - -node_modules -dist - -.env - -storybook-static -*storybook.log -.DS_Store diff --git a/HDesign/.npmignore b/HDesign/.npmignore deleted file mode 100644 index 363c89306..000000000 --- a/HDesign/.npmignore +++ /dev/null @@ -1,7 +0,0 @@ -node_modules/ -src/ -tsconfig.json -.storybook/ -.eslintrc.json -.prettierrc -webpack.config.js \ No newline at end of file diff --git a/HDesign/.npmrc b/HDesign/.npmrc deleted file mode 100644 index ece05f588..000000000 --- a/HDesign/.npmrc +++ /dev/null @@ -1,2 +0,0 @@ -engine-strict = true -legacy-peer-deps = true diff --git a/HDesign/.prettierrc b/HDesign/.prettierrc deleted file mode 100644 index c025201f4..000000000 --- a/HDesign/.prettierrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "singleQuote": true, - "trailingComma": "all", - "printWidth": 120, - "tabWidth": 2, - "semi": true, - "arrowParens": "avoid", - "endOfLine": "auto", - "jsxSingleQuote": false, - "bracketSpacing": false, - "proseWrap": "preserve" -} diff --git a/HDesign/.storybook/main.ts b/HDesign/.storybook/main.ts deleted file mode 100644 index 0a8a9a7c4..000000000 --- a/HDesign/.storybook/main.ts +++ /dev/null @@ -1,46 +0,0 @@ -/** @type { import('@storybook/react-webpack5').StorybookConfig } */ -import type {StorybookConfig} from '@storybook/react-webpack5'; -import path from 'path'; - -const config: StorybookConfig = { - stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], - addons: [ - '@storybook/addon-webpack5-compiler-swc', - '@storybook/addon-onboarding', - '@storybook/addon-links', - '@storybook/addon-essentials', - '@chromatic-com/storybook', - '@storybook/addon-interactions', - ], - framework: { - name: '@storybook/react-webpack5', - options: {}, - }, - webpackFinal: async config => { - if (config.resolve) { - config.resolve.alias = { - ...config.resolve.alias, - '@': path.resolve(__dirname, '../src'), - '@components': path.resolve(__dirname, '../src/components'), - '@assets': path.resolve(__dirname, '../src/assets'), - '@token': path.resolve(__dirname, '../src/token'), - '@theme': path.resolve(__dirname, '../src/theme'), - }; - } - - config.module = config.module || {}; - config.module.rules = config.module.rules || []; - - const imageRule = config.module.rules.find(rule => rule?.['test']?.test('.svg')); - if (imageRule) { - imageRule['exclude'] = /\.svg$/; - } - - config.module.rules.push({ - test: /\.svg$/, - use: ['@svgr/webpack'], - }); - return config; - }, -}; -export default config; diff --git a/HDesign/.storybook/preview.tsx b/HDesign/.storybook/preview.tsx deleted file mode 100644 index 1b16d7c39..000000000 --- a/HDesign/.storybook/preview.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import React from 'react'; - -import type {Preview} from '@storybook/react'; -import {HDesignProvider} from '../src/theme/HDesignProvider'; - -const preview: Preview = { - parameters: { - controls: { - matchers: { - color: /(background|color)$/i, - date: /Date$/i, - }, - }, - viewport: { - defaultViewport: { - styles: { - width: '375px', - height: '812px', - }, - }, - }, - backgrounds: { - default: 'gray', - values: [ - { - name: 'gray', - value: '#f3f3f3', - }, - ], - }, - }, - decorators: [ - Story => ( - <HDesignProvider> - <Story /> - </HDesignProvider> - ), - ], -}; - -export default preview; diff --git a/HDesign/eslint.config.mjs b/HDesign/eslint.config.mjs deleted file mode 100644 index 96b3da00a..000000000 --- a/HDesign/eslint.config.mjs +++ /dev/null @@ -1,151 +0,0 @@ -import path from 'node:path'; -import {fileURLToPath} from 'node:url'; - -import {fixupConfigRules, fixupPluginRules} from '@eslint/compat'; -import react from 'eslint-plugin-react'; -import typescriptEslint from '@typescript-eslint/eslint-plugin'; -import _import from 'eslint-plugin-import'; -import prettier from 'eslint-plugin-prettier'; -import tsParser from '@typescript-eslint/parser'; -import js from '@eslint/js'; -import {FlatCompat} from '@eslint/eslintrc'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); -const compat = new FlatCompat({ - baseDirectory: __dirname, - recommendedConfig: js.configs.recommended, - allConfig: js.configs.all, -}); - -export default [ - ...fixupConfigRules( - compat.extends( - 'eslint:recommended', - 'plugin:react/recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:react-hooks/recommended', - 'plugin:import/typescript', - 'plugin:import/recommended', - 'plugin:import/errors', - 'plugin:import/warnings', - 'prettier', - 'plugin:prettier/recommended', - ), - ), - { - plugins: { - react: fixupPluginRules(react), - '@typescript-eslint': fixupPluginRules(typescriptEslint), - import: fixupPluginRules(_import), - prettier: fixupPluginRules(prettier), - }, - - languageOptions: { - parser: tsParser, - }, - - settings: { - 'import/resolver': { - node: { - extensions: ['.js', '.jsx', '.ts', '.tsx'], - }, - - typescript: { - directory: './lib', - }, - }, - - 'import/parsers': { - '@typescript-eslint/parser': ['.ts', '.tsx'], - }, - }, - - rules: { - 'no-use-before-define': 0, - 'prettier/prettier': 'error', - 'react/react-in-jsx-scope': 'off', - 'react/prop-types': 'off', - 'import/prefer-default-export': 0, - 'import/no-named-as-default': 0, - 'import/namespace': 0, - 'import/extensions': 0, - 'import/no-cycle': 0, - 'react/no-unknown-property': 0, - 'react/jsx-filename-extension': [1, {extensions: ['.ts', '.tsx']}], - 'react/function-component-definition': 0, - 'react/jsx-props-no-spreading': 0, - 'react/jsx-key': 0, - 'react/button-has-type': 'off', - 'no-shadow': 0, - 'no-console': 0, - 'no-alert': 0, - 'react/no-children-prop': 'off', - 'react/no-array-index-key': 'off', - 'react-hooks/exhaustive-deps': 'off', - 'react-hooks/rules-of-hooks': 'off', - 'react/jsx-no-useless-fragment': 'off', - 'react/jsx-no-constructed-context-values': 'off', - 'jsx-a11y/click-events-have-key-events': 'off', - 'jsx-a11y/no-static-element-interactions': 'off', - - '@typescript-eslint/no-unused-vars': 0, - - // 'react/jsx-uses-vars': 'error', - // '@typescript-eslint/no-use-before-define': ['error'], - // '@typescript-eslint/explicit-module-boundary-types': 'error', - - 'import/order': [ - 'error', - { - 'newlines-between': 'always', - - groups: ['type', 'builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'unknown'], - - pathGroups: [ - { - pattern: 'react*', - group: 'external', - position: 'before', - }, - { - pattern: '@components/*', - group: 'internal', - position: 'after', - }, - { - pattern: '@layouts/*', - group: 'internal', - position: 'after', - }, - { - pattern: '@assets/*', - group: 'internal', - position: 'after', - }, - { - pattern: '@theme/*', - group: 'internal', - position: 'after', - }, - { - pattern: '@token/*', - group: 'internal', - position: 'after', - }, - { - pattern: '@types/*', - group: 'internal', - position: 'after', - }, - { - pattern: '@utils/*', - group: 'internal', - position: 'after', - }, - ], - }, - ], - }, - }, -]; diff --git a/HDesign/package-lock.json b/HDesign/package-lock.json deleted file mode 100644 index 3747523df..000000000 --- a/HDesign/package-lock.json +++ /dev/null @@ -1,13638 +0,0 @@ -{ - "name": "haengdong-design", - "version": "0.1.35", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "haengdong-design", - "version": "0.1.35", - "license": "ISC", - "dependencies": { - "@emotion/react": "^11.11.4", - "@svgr/webpack": "^8.1.0", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "react-router-dom": "^6.24.1" - }, - "devDependencies": { - "@chromatic-com/storybook": "^1.6.1", - "@eslint/compat": "^1.1.0", - "@eslint/js": "^9.6.0", - "@storybook/addon-essentials": "^8.2.2", - "@storybook/addon-interactions": "^8.2.2", - "@storybook/addon-links": "^8.2.2", - "@storybook/addon-onboarding": "^8.2.2", - "@storybook/addon-webpack5-compiler-swc": "^1.0.4", - "@storybook/blocks": "^8.2.2", - "@storybook/react": "^8.2.2", - "@storybook/react-webpack5": "^8.2.3", - "@storybook/test": "^8.2.2", - "@types/react": "^18.3.3", - "@types/react-dom": "^18.3.0", - "@typescript-eslint/eslint-plugin": "^7.16.0", - "@typescript-eslint/parser": "^7.16.0", - "eslint": "^9.7.0", - "eslint-config-prettier": "^9.1.0", - "eslint-import-resolver-typescript": "^3.6.1", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jsx-a11y": "^6.9.0", - "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-react": "^7.34.4", - "eslint-plugin-react-hooks": "^4.6.2", - "eslint-plugin-storybook": "^0.8.0", - "file-loader": "^6.2.0", - "globals": "^15.8.0", - "prettier": "3.3.2", - "storybook": "^8.2.2", - "storybook-addon-react-router-v6": "^2.0.15", - "ts-loader": "^9.5.1", - "tsc-alias": "^1.8.10", - "typescript": "^5.5.3", - "typescript-eslint": "^7.16.0" - }, - "engines": { - "node": ">=20.15.1", - "npm": ">=10.7.0" - } - }, - "node_modules/@adobe/css-tools": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.0.tgz", - "integrity": "sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==", - "dev": true - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", - "dependencies": { - "@babel/highlight": "^7.24.7", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.9.tgz", - "integrity": "sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz", - "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.9", - "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-module-transforms": "^7.24.9", - "@babel/helpers": "^7.24.8", - "@babel/parser": "^7.24.8", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.8", - "@babel/types": "^7.24.9", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" - }, - "node_modules/@babel/core/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@babel/core/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.9.tgz", - "integrity": "sha512-G8v3jRg+z8IwY1jHFxvCNhOPYPterE4XljNgdGTYfSTtzzwjIswIzIaSPSLs3R7yFuqnqNeay5rjICfqVr+/6A==", - "dependencies": { - "@babel/types": "^7.24.9", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", - "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", - "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz", - "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==", - "dependencies": { - "@babel/compat-data": "^7.24.8", - "@babel/helper-validator-option": "^7.24.8", - "browserslist": "^4.23.1", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.8.tgz", - "integrity": "sha512-4f6Oqnmyp2PP3olgUMmOwC3akxSm5aBYraQ6YDdKy7NcAMkDECHWG0DEnV6M2UAkERgIBhYt8S27rURPg7SxWA==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-member-expression-to-functions": "^7.24.8", - "@babel/helper-optimise-call-expression": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.7.tgz", - "integrity": "sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "regexpu-core": "^5.3.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", - "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", - "dependencies": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", - "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", - "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", - "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", - "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", - "dependencies": { - "@babel/traverse": "^7.24.8", - "@babel/types": "^7.24.8" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz", - "integrity": "sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==", - "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", - "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", - "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.7.tgz", - "integrity": "sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-wrap-function": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz", - "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==", - "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-member-expression-to-functions": "^7.24.7", - "@babel/helper-optimise-call-expression": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", - "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", - "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", - "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", - "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.7.tgz", - "integrity": "sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==", - "dependencies": { - "@babel/helper-function-name": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz", - "integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==", - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.8" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", - "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.7.tgz", - "integrity": "sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==", - "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.7.tgz", - "integrity": "sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", - "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.7.tgz", - "integrity": "sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==", - "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-flow": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.24.7.tgz", - "integrity": "sha512-9G8GYT/dxn/D1IIKOUBmGX0mnmj46mGH9NnZyJLwtCpgh5f7D2VbuKodb+2s9m1Yavh1s7ASQN8lf0eqrb1LTw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", - "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", - "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", - "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", - "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-unicode-sets-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", - "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", - "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.7.tgz", - "integrity": "sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==", - "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-remap-async-to-generator": "^7.24.7", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", - "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", - "dependencies": { - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-remap-async-to-generator": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", - "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.7.tgz", - "integrity": "sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz", - "integrity": "sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", - "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.8.tgz", - "integrity": "sha512-VXy91c47uujj758ud9wx+OMgheXm4qJfyhj1P18YvlrQkNOSrwsteHk+EFS3OMGfhMhpZa0A+81eE7G4QC+3CA==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-replace-supers": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-classes/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", - "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/template": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", - "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", - "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", - "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", - "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", - "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", - "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", - "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-flow-strip-types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.24.7.tgz", - "integrity": "sha512-cjRKJ7FobOH2eakx7Ja+KpJRj8+y+/SiB3ooYm/n2UJfxu0oEaOoxOinitkJcPqv9KxS0kxTGPUaR7L2XcXDXA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-flow": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", - "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.7.tgz", - "integrity": "sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==", - "dependencies": { - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", - "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.7.tgz", - "integrity": "sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", - "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", - "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", - "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", - "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", - "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", - "dependencies": { - "@babel/helper-module-transforms": "^7.24.8", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-simple-access": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.7.tgz", - "integrity": "sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==", - "dependencies": { - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", - "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", - "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", - "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", - "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", - "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", - "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", - "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", - "dependencies": { - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", - "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", - "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", - "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", - "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz", - "integrity": "sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", - "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", - "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-constant-elements": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.24.7.tgz", - "integrity": "sha512-7LidzZfUXyfZ8/buRW6qIIHBY8wAZ1OrY9c/wTr8YhZ6vMPo+Uc/CVFLYY1spZrEQlD4w5u8wjqk5NQ3OVqQKA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.7.tgz", - "integrity": "sha512-H/Snz9PFxKsS1JLI4dJLtnJgCJRoo0AUm3chP6NYr+9En1JMKloheEiLIhlp5MDVznWo+H3AAC1Mc8lmUEpsgg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.24.7.tgz", - "integrity": "sha512-+Dj06GDZEFRYvclU6k4bme55GKBEWUmByM/eoKuqg4zTNQHiApWRhQph5fxQB2wAEFvRzL1tOEj1RJ19wJrhoA==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-jsx": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.24.7.tgz", - "integrity": "sha512-QG9EnzoGn+Qar7rxuW+ZOsbWOt56FvvI93xInqsZDC5fsekx1AlIO4KIJ5M+D0p0SqSH156EpmZyXq630B8OlQ==", - "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.7.tgz", - "integrity": "sha512-PLgBVk3fzbmEjBJ/u8kFzOqS9tUeDjiaWud/rRym/yjCo/M9cASPlnrd2ZmmZpQT40fOOrvR8jh+n8jikrOhNA==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", - "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "regenerator-transform": "^0.15.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", - "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", - "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", - "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", - "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", - "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", - "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typescript": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.8.tgz", - "integrity": "sha512-CgFgtN61BbdOGCP4fLaAMOPkzWUh6yQZNMr5YSt8uz2cZSSiQONCQFWqsE4NeVfOIhqDOlS9CR3WD91FzMeB2Q==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-create-class-features-plugin": "^7.24.8", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/plugin-syntax-typescript": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", - "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", - "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", - "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz", - "integrity": "sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.8.tgz", - "integrity": "sha512-vObvMZB6hNWuDxhSaEPTKCwcqkAIuDtE+bQGn4XMXne1DSLzFVY8Vmj1bm+mUQXYNN8NmaQEO+r8MMbzPr1jBQ==", - "dependencies": { - "@babel/compat-data": "^7.24.8", - "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-validator-option": "^7.24.8", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.7", - "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.24.7", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.24.7", - "@babel/plugin-transform-async-generator-functions": "^7.24.7", - "@babel/plugin-transform-async-to-generator": "^7.24.7", - "@babel/plugin-transform-block-scoped-functions": "^7.24.7", - "@babel/plugin-transform-block-scoping": "^7.24.7", - "@babel/plugin-transform-class-properties": "^7.24.7", - "@babel/plugin-transform-class-static-block": "^7.24.7", - "@babel/plugin-transform-classes": "^7.24.8", - "@babel/plugin-transform-computed-properties": "^7.24.7", - "@babel/plugin-transform-destructuring": "^7.24.8", - "@babel/plugin-transform-dotall-regex": "^7.24.7", - "@babel/plugin-transform-duplicate-keys": "^7.24.7", - "@babel/plugin-transform-dynamic-import": "^7.24.7", - "@babel/plugin-transform-exponentiation-operator": "^7.24.7", - "@babel/plugin-transform-export-namespace-from": "^7.24.7", - "@babel/plugin-transform-for-of": "^7.24.7", - "@babel/plugin-transform-function-name": "^7.24.7", - "@babel/plugin-transform-json-strings": "^7.24.7", - "@babel/plugin-transform-literals": "^7.24.7", - "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", - "@babel/plugin-transform-member-expression-literals": "^7.24.7", - "@babel/plugin-transform-modules-amd": "^7.24.7", - "@babel/plugin-transform-modules-commonjs": "^7.24.8", - "@babel/plugin-transform-modules-systemjs": "^7.24.7", - "@babel/plugin-transform-modules-umd": "^7.24.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", - "@babel/plugin-transform-new-target": "^7.24.7", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", - "@babel/plugin-transform-numeric-separator": "^7.24.7", - "@babel/plugin-transform-object-rest-spread": "^7.24.7", - "@babel/plugin-transform-object-super": "^7.24.7", - "@babel/plugin-transform-optional-catch-binding": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.8", - "@babel/plugin-transform-parameters": "^7.24.7", - "@babel/plugin-transform-private-methods": "^7.24.7", - "@babel/plugin-transform-private-property-in-object": "^7.24.7", - "@babel/plugin-transform-property-literals": "^7.24.7", - "@babel/plugin-transform-regenerator": "^7.24.7", - "@babel/plugin-transform-reserved-words": "^7.24.7", - "@babel/plugin-transform-shorthand-properties": "^7.24.7", - "@babel/plugin-transform-spread": "^7.24.7", - "@babel/plugin-transform-sticky-regex": "^7.24.7", - "@babel/plugin-transform-template-literals": "^7.24.7", - "@babel/plugin-transform-typeof-symbol": "^7.24.8", - "@babel/plugin-transform-unicode-escapes": "^7.24.7", - "@babel/plugin-transform-unicode-property-regex": "^7.24.7", - "@babel/plugin-transform-unicode-regex": "^7.24.7", - "@babel/plugin-transform-unicode-sets-regex": "^7.24.7", - "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.10.4", - "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.37.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/preset-flow": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.24.7.tgz", - "integrity": "sha512-NL3Lo0NorCU607zU3NwRyJbpaB6E3t0xtd3LfAQKDfkeX4/ggcDXvkmkW42QWT5owUeW/jAe4hn+2qvkV1IbfQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "@babel/plugin-transform-flow-strip-types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.6-no-external-plugins", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", - "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@babel/preset-react": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.24.7.tgz", - "integrity": "sha512-AAH4lEkpmzFWrGVlHaxJB7RLH21uPQ9+He+eFLWHmF9IuFQVugz8eAsamaW0DXRrTfco5zj1wWtpdcXJUOfsag==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "@babel/plugin-transform-react-display-name": "^7.24.7", - "@babel/plugin-transform-react-jsx": "^7.24.7", - "@babel/plugin-transform-react-jsx-development": "^7.24.7", - "@babel/plugin-transform-react-pure-annotations": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-typescript": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.7.tgz", - "integrity": "sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "@babel/plugin-syntax-jsx": "^7.24.7", - "@babel/plugin-transform-modules-commonjs": "^7.24.7", - "@babel/plugin-transform-typescript": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/register": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.24.6.tgz", - "integrity": "sha512-WSuFCc2wCqMeXkz/i3yfAAsxwWflEgbVkZzivgAmXl/MxrXeoYFZOOPllbC8R8WTF7u61wSRQtDVZ1879cdu6w==", - "dev": true, - "dependencies": { - "clone-deep": "^4.0.1", - "find-cache-dir": "^2.0.0", - "make-dir": "^2.1.0", - "pirates": "^4.0.6", - "source-map-support": "^0.5.16" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/register/node_modules/find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@babel/register/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@babel/register/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@babel/register/node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@babel/register/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@babel/register/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/register/node_modules/pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@babel/register/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/@babel/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" - }, - "node_modules/@babel/runtime": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", - "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", - "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz", - "integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==", - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.8", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/parser": "^7.24.8", - "@babel/types": "^7.24.8", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/traverse/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/@babel/types": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.9.tgz", - "integrity": "sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==", - "dependencies": { - "@babel/helper-string-parser": "^7.24.8", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@base2/pretty-print-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz", - "integrity": "sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==", - "dev": true - }, - "node_modules/@chromatic-com/storybook": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@chromatic-com/storybook/-/storybook-1.6.1.tgz", - "integrity": "sha512-x1x1NB3j4xpfeSWKr96emc+7ZvfsvH+/WVb3XCjkB24PPbT8VZXb3mJSAQMrSzuQ8+eQE9kDogYHH9Fj3tb/Cw==", - "dev": true, - "dependencies": { - "chromatic": "^11.4.0", - "filesize": "^10.0.12", - "jsonfile": "^6.1.0", - "react-confetti": "^6.1.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=16.0.0", - "yarn": ">=1.22.18" - } - }, - "node_modules/@chromatic-com/storybook/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@chromatic-com/storybook/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@emotion/babel-plugin": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", - "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", - "dependencies": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/runtime": "^7.18.3", - "@emotion/hash": "^0.9.1", - "@emotion/memoize": "^0.8.1", - "@emotion/serialize": "^1.1.2", - "babel-plugin-macros": "^3.1.0", - "convert-source-map": "^1.5.0", - "escape-string-regexp": "^4.0.0", - "find-root": "^1.1.0", - "source-map": "^0.5.7", - "stylis": "4.2.0" - } - }, - "node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@emotion/babel-plugin/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@emotion/cache": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", - "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", - "dependencies": { - "@emotion/memoize": "^0.8.1", - "@emotion/sheet": "^1.2.2", - "@emotion/utils": "^1.2.1", - "@emotion/weak-memoize": "^0.3.1", - "stylis": "4.2.0" - } - }, - "node_modules/@emotion/hash": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", - "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" - }, - "node_modules/@emotion/memoize": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", - "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" - }, - "node_modules/@emotion/react": { - "version": "11.11.4", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.4.tgz", - "integrity": "sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==", - "dependencies": { - "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.11.0", - "@emotion/cache": "^11.11.0", - "@emotion/serialize": "^1.1.3", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", - "@emotion/utils": "^1.2.1", - "@emotion/weak-memoize": "^0.3.1", - "hoist-non-react-statics": "^3.3.1" - }, - "peerDependencies": { - "react": ">=16.8.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@emotion/serialize": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.4.tgz", - "integrity": "sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ==", - "dependencies": { - "@emotion/hash": "^0.9.1", - "@emotion/memoize": "^0.8.1", - "@emotion/unitless": "^0.8.1", - "@emotion/utils": "^1.2.1", - "csstype": "^3.0.2" - } - }, - "node_modules/@emotion/sheet": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", - "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" - }, - "node_modules/@emotion/unitless": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", - "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" - }, - "node_modules/@emotion/use-insertion-effect-with-fallbacks": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", - "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", - "peerDependencies": { - "react": ">=16.8.0" - } - }, - "node_modules/@emotion/utils": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", - "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" - }, - "node_modules/@emotion/weak-memoize": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", - "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", - "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/compat": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.1.0.tgz", - "integrity": "sha512-s9Wi/p25+KbzxKlDm3VshQdImhWk+cbdblhwGNnyCU5lpSwtWa4v7VQCxSki0FAUrGA3s8nCWgYzAH41mwQVKQ==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", - "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", - "dev": true, - "dependencies": { - "@eslint/object-schema": "^2.1.4", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/config-array/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/config-array/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@eslint/eslintrc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@eslint/js": { - "version": "9.7.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.7.0.tgz", - "integrity": "sha512-ChuWDQenef8OSFnvuxv0TCVxEwmu3+hPNKvM9B34qpM0rDRbjL8t5QkQeHHeAfsKQjuH9wS82WeCi1J/owatng==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", - "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", - "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", - "dev": true, - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@mdx-js/react": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.0.1.tgz", - "integrity": "sha512-9ZrPIU4MGf6et1m1ov3zKf+q9+deetI51zprKB1D/z3NOb+rUxxtEl3mCjW5wTGh6VhRdwPueh1oRzi6ezkA8A==", - "dev": true, - "dependencies": { - "@types/mdx": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - }, - "peerDependencies": { - "@types/react": ">=16", - "react": ">=16" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/@remix-run/router": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.17.1.tgz", - "integrity": "sha512-mCOMec4BKd6BRGBZeSnGiIgwsbLGp3yhVqAD8H+PxiRNEHgDpZb8J1TnrSDlg97t0ySKMQJTHCWBCmBpSmkF6Q==", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true - }, - "node_modules/@sindresorhus/merge-streams": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", - "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@storybook/addon-actions": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-8.2.2.tgz", - "integrity": "sha512-SN4cSRt3f0qXi5te+yhMseSdQuZntA8lGlASbRmN77YQTpIaGsNiH88xFoky0s9qz531hiRfU1R0ZSMylBwSKw==", - "dev": true, - "dependencies": { - "@storybook/global": "^5.0.0", - "@types/uuid": "^9.0.1", - "dequal": "^2.0.2", - "polished": "^4.2.2", - "uuid": "^9.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.2" - } - }, - "node_modules/@storybook/addon-actions/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "dev": true, - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@storybook/addon-backgrounds": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-8.2.2.tgz", - "integrity": "sha512-m/xJe7uKL+kfJx7pQcHwAeIvJ3tdLIpDGrMAVDNDJHcAxfe44cFjIInaV/1HKf3y5Awap+DZFW66ekkxuI9zzA==", - "dev": true, - "dependencies": { - "@storybook/global": "^5.0.0", - "memoizerific": "^1.11.3", - "ts-dedent": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.2" - } - }, - "node_modules/@storybook/addon-controls": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-8.2.2.tgz", - "integrity": "sha512-y241aOANGzT5XBADUIvALwG/xF5eC6UItzmWJaFvOzSBCq74GIA0+Hu9atyFdvFQbXOrdvPWC4jR+9iuBFRxAA==", - "dev": true, - "dependencies": { - "dequal": "^2.0.2", - "lodash": "^4.17.21", - "ts-dedent": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.2" - } - }, - "node_modules/@storybook/addon-docs": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-8.2.2.tgz", - "integrity": "sha512-qk/yjAR9RpsSrKLLbeCgb6u58c8TmYqyJSnXgbAozZZNKHBWlIpvZ/hTNYud8qo0coPlxnLdjnZf32TykWGlAg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.24.4", - "@mdx-js/react": "^3.0.0", - "@storybook/blocks": "8.2.2", - "@storybook/csf-plugin": "8.2.2", - "@storybook/global": "^5.0.0", - "@storybook/react-dom-shim": "8.2.2", - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "fs-extra": "^11.1.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", - "rehype-external-links": "^3.0.0", - "rehype-slug": "^6.0.0", - "ts-dedent": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.2" - } - }, - "node_modules/@storybook/addon-docs/node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/@storybook/addon-essentials": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/addon-essentials/-/addon-essentials-8.2.2.tgz", - "integrity": "sha512-yN//BFMbSvNV0+Sll2hcKmgJX06TUKQDm6pZimUjkXczFtOmK7K/UdDmKjWS+qjhfJdWpxdRoEpxoHvvRmNfsA==", - "dev": true, - "dependencies": { - "@storybook/addon-actions": "8.2.2", - "@storybook/addon-backgrounds": "8.2.2", - "@storybook/addon-controls": "8.2.2", - "@storybook/addon-docs": "8.2.2", - "@storybook/addon-highlight": "8.2.2", - "@storybook/addon-measure": "8.2.2", - "@storybook/addon-outline": "8.2.2", - "@storybook/addon-toolbars": "8.2.2", - "@storybook/addon-viewport": "8.2.2", - "ts-dedent": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.2" - } - }, - "node_modules/@storybook/addon-highlight": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/addon-highlight/-/addon-highlight-8.2.2.tgz", - "integrity": "sha512-yDTRzzL+IJAymgY32xoZl09BGBVmPOUV2wVNGYcZkkBLvz2GSQMTfUe1/7F4jAx//+rFBu48/MQzsTC7Bk8kPw==", - "dev": true, - "dependencies": { - "@storybook/global": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.2" - } - }, - "node_modules/@storybook/addon-interactions": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/addon-interactions/-/addon-interactions-8.2.2.tgz", - "integrity": "sha512-zRRuUwm/l41JtTUgjIoQTUgLT99Hsdz9cqKca/8NYo1MGBdEcKE41DH4aBIzKaOKFu7p9q00/o/X1EqYX4LMUA==", - "dev": true, - "dependencies": { - "@storybook/global": "^5.0.0", - "@storybook/instrumenter": "8.2.2", - "@storybook/test": "8.2.2", - "polished": "^4.2.2", - "ts-dedent": "^2.2.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.2" - } - }, - "node_modules/@storybook/addon-links": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-8.2.2.tgz", - "integrity": "sha512-eGh7O7SgTJMtnuXC0HlRPOegu1njcJS2cnVqjbzjvjxsPSBhbHpdYMi9Q9E7al/FKuqMUOjIR9YLIlmK1AJaqA==", - "dev": true, - "dependencies": { - "@storybook/csf": "0.1.11", - "@storybook/global": "^5.0.0", - "ts-dedent": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^8.2.2" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - } - } - }, - "node_modules/@storybook/addon-measure": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/addon-measure/-/addon-measure-8.2.2.tgz", - "integrity": "sha512-3rCo/aMltt5FrBVdr2dYlD8HlE2q9TLKGJZnwh9on4QyL6ArHbdYw0LmyHe/LrFahJ49w1XQZBMSJcAdRkkS7w==", - "dev": true, - "dependencies": { - "@storybook/global": "^5.0.0", - "tiny-invariant": "^1.3.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.2" - } - }, - "node_modules/@storybook/addon-onboarding": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/addon-onboarding/-/addon-onboarding-8.2.2.tgz", - "integrity": "sha512-dCdE8Mt/JW6cq6dY7co35Sul/bAkUT3ixaxBrUagFUYUQ/PTYM6p4/B+45RURD5S9z8LVHH1rVgmEeScm3U78w==", - "dev": true, - "dependencies": { - "react-confetti": "^6.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.2" - } - }, - "node_modules/@storybook/addon-outline": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/addon-outline/-/addon-outline-8.2.2.tgz", - "integrity": "sha512-Y+PQtfTNO8GLX5nz+3x5AMfHNvdGvBXazJ29+Rl1ygYN1+Q9ZhRJDE1kAK0wLxb7CG14peAgdYEaQb3Rduv7HQ==", - "dev": true, - "dependencies": { - "@storybook/global": "^5.0.0", - "ts-dedent": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.2" - } - }, - "node_modules/@storybook/addon-toolbars": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/addon-toolbars/-/addon-toolbars-8.2.2.tgz", - "integrity": "sha512-JGOueOc3EPljlCl9dVSQee0aMYoqGNvN0UH+R6wYJ3bDZ+tUG/iYpsZVPUOvS8vzp3Imk5Is1kzQbQYJtzdGLg==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.2" - } - }, - "node_modules/@storybook/addon-viewport": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/addon-viewport/-/addon-viewport-8.2.2.tgz", - "integrity": "sha512-gkZ8bsjGGP0NuevkT2iKC+szezSy+w4BrBDknf490mRU2K/B2e7TGojf/j/AtxzILMzD4IKzKUXbE/zwcqjZvA==", - "dev": true, - "dependencies": { - "memoizerific": "^1.11.3" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.2" - } - }, - "node_modules/@storybook/addon-webpack5-compiler-swc": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@storybook/addon-webpack5-compiler-swc/-/addon-webpack5-compiler-swc-1.0.4.tgz", - "integrity": "sha512-S/ypdAK9oqwUAt3ZOn44qi3RWdH5uBLbBgtfHSXckqTpQRu7F7A9bRzjK+H5ti4xVADRhxu/xzIBwxWgcCeIXA==", - "dev": true, - "dependencies": { - "@swc/core": "1.5.7", - "swc-loader": "^0.2.3" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@storybook/blocks": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/blocks/-/blocks-8.2.2.tgz", - "integrity": "sha512-av0Tryg4toDl2L/d1ABErtsAk9wvM1su6+M4wq5/Go50sk5IjGTldhbZFa9zNOohxLkZwaj0Q5xAgJ1Y+m5KrQ==", - "dev": true, - "dependencies": { - "@storybook/csf": "0.1.11", - "@storybook/global": "^5.0.0", - "@storybook/icons": "^1.2.5", - "@types/lodash": "^4.14.167", - "color-convert": "^2.0.1", - "dequal": "^2.0.2", - "lodash": "^4.17.21", - "markdown-to-jsx": "^7.4.5", - "memoizerific": "^1.11.3", - "polished": "^4.2.2", - "react-colorful": "^5.1.2", - "telejson": "^7.2.0", - "ts-dedent": "^2.0.0", - "util-deprecate": "^1.0.2" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^8.2.2" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } - } - }, - "node_modules/@storybook/builder-webpack5": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/@storybook/builder-webpack5/-/builder-webpack5-8.2.3.tgz", - "integrity": "sha512-yU9rtcVpo12vD8m/nbdepyJ09K937ZnSsrvIM9XfzbxXA/+p4Cov9Rjg1VfoWyRd1ApxaztSktQlawBlb6bKEA==", - "dev": true, - "dependencies": { - "@storybook/core-webpack": "8.2.3", - "@types/node": "^18.0.0", - "@types/semver": "^7.3.4", - "browser-assert": "^1.2.1", - "case-sensitive-paths-webpack-plugin": "^2.4.0", - "cjs-module-lexer": "^1.2.3", - "constants-browserify": "^1.0.0", - "css-loader": "^6.7.1", - "es-module-lexer": "^1.5.0", - "express": "^4.19.2", - "fork-ts-checker-webpack-plugin": "^8.0.0", - "fs-extra": "^11.1.0", - "html-webpack-plugin": "^5.5.0", - "magic-string": "^0.30.5", - "path-browserify": "^1.0.1", - "process": "^0.11.10", - "semver": "^7.3.7", - "style-loader": "^3.3.1", - "terser-webpack-plugin": "^5.3.1", - "ts-dedent": "^2.0.0", - "url": "^0.11.0", - "util": "^0.12.4", - "util-deprecate": "^1.0.2", - "webpack": "5", - "webpack-dev-middleware": "^6.1.2", - "webpack-hot-middleware": "^2.25.1", - "webpack-virtual-modules": "^0.6.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.3" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/@types/node": { - "version": "18.19.39", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", - "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "dev": true, - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/fork-ts-checker-webpack-plugin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-8.0.0.tgz", - "integrity": "sha512-mX3qW3idpueT2klaQXBzrIM/pHw+T0B/V9KHEvNrqijTq9NFnMZU6oreVxDYcf33P8a5cW+67PjodNHthGnNVg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.7", - "chalk": "^4.1.2", - "chokidar": "^3.5.3", - "cosmiconfig": "^7.0.1", - "deepmerge": "^4.2.2", - "fs-extra": "^10.0.0", - "memfs": "^3.4.1", - "minimatch": "^3.0.4", - "node-abort-controller": "^3.0.1", - "schema-utils": "^3.1.1", - "semver": "^7.3.5", - "tapable": "^2.2.1" - }, - "engines": { - "node": ">=12.13.0", - "yarn": ">=1.0.0" - }, - "peerDependencies": { - "typescript": ">3.6.0", - "webpack": "^5.11.0" - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/@storybook/builder-webpack5/node_modules/memfs": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", - "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", - "dev": true, - "dependencies": { - "fs-monkey": "^1.0.4" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/webpack-dev-middleware": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.3.tgz", - "integrity": "sha512-A4ChP0Qj8oGociTs6UdlRUGANIGrCDL3y+pmQMc+dSsraXHCatFpmMey4mYELA+juqwUqwQsUgJJISXl1KWmiw==", - "dev": true, - "dependencies": { - "colorette": "^2.0.10", - "memfs": "^3.4.12", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - } - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/webpack-dev-middleware/node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/@storybook/codemod": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/codemod/-/codemod-8.2.2.tgz", - "integrity": "sha512-wRUVKLHVUhbLJYKW3QOufUxJGwaUT4jTCD8+HOGpHPdJO3NrwXu186xt4tuPZO2Y/NnacPeCQPsaK5ok4O8o7A==", - "dev": true, - "dependencies": { - "@babel/core": "^7.24.4", - "@babel/preset-env": "^7.24.4", - "@babel/types": "^7.24.0", - "@storybook/core": "8.2.2", - "@storybook/csf": "0.1.11", - "@types/cross-spawn": "^6.0.2", - "cross-spawn": "^7.0.3", - "globby": "^14.0.1", - "jscodeshift": "^0.15.1", - "lodash": "^4.17.21", - "prettier": "^3.1.1", - "recast": "^0.23.5", - "tiny-invariant": "^1.3.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - } - }, - "node_modules/@storybook/codemod/node_modules/globby": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", - "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", - "dev": true, - "dependencies": { - "@sindresorhus/merge-streams": "^2.1.0", - "fast-glob": "^3.3.2", - "ignore": "^5.2.4", - "path-type": "^5.0.0", - "slash": "^5.1.0", - "unicorn-magic": "^0.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@storybook/codemod/node_modules/path-type": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", - "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@storybook/codemod/node_modules/slash": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", - "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", - "dev": true, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@storybook/core": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/core/-/core-8.2.2.tgz", - "integrity": "sha512-L4ojYI+Os/i5bCReDIlFgEDQSS94mbJlNU9WRzEGZpqNC5/hbFEC9Tip7P1MiRx9NrewkzU7b+UCP7mi3e4drQ==", - "dev": true, - "dependencies": { - "@storybook/csf": "0.1.11", - "@types/express": "^4.17.21", - "@types/node": "^18.0.0", - "browser-assert": "^1.2.1", - "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0", - "esbuild-register": "^3.5.0", - "express": "^4.19.2", - "process": "^0.11.10", - "recast": "^0.23.5", - "util": "^0.12.4", - "ws": "^8.2.3" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - } - }, - "node_modules/@storybook/core-webpack": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/@storybook/core-webpack/-/core-webpack-8.2.3.tgz", - "integrity": "sha512-0M4mJM6i4Oqp1javRMg/8wJW7VJ6p6Z8GKp6evfHLEWZAzdnexQIkPd5FFaDlFXbQNH1H0oJ+6ei4nIBtEegKg==", - "dev": true, - "dependencies": { - "@types/node": "^18.0.0", - "ts-dedent": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.3" - } - }, - "node_modules/@storybook/core-webpack/node_modules/@types/node": { - "version": "18.19.39", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", - "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@storybook/core/node_modules/@types/node": { - "version": "18.19.39", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", - "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@storybook/csf": { - "version": "0.1.11", - "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.1.11.tgz", - "integrity": "sha512-dHYFQH3mA+EtnCkHXzicbLgsvzYjcDJ1JWsogbItZogkPHgSJM/Wr71uMkcvw8v9mmCyP4NpXJuu6bPoVsOnzg==", - "dev": true, - "dependencies": { - "type-fest": "^2.19.0" - } - }, - "node_modules/@storybook/csf-plugin": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-8.2.2.tgz", - "integrity": "sha512-3K2RUpDDvq3DT46qAIj2VBC+fzTTebRUcZUsRfS6G1AzaX9p25iClEHiwcJacFkgQKhkci8A/Ly3Z4JJ3b4Pgw==", - "dev": true, - "dependencies": { - "unplugin": "^1.3.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.2" - } - }, - "node_modules/@storybook/global": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@storybook/global/-/global-5.0.0.tgz", - "integrity": "sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==", - "dev": true - }, - "node_modules/@storybook/icons": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/@storybook/icons/-/icons-1.2.9.tgz", - "integrity": "sha512-cOmylsz25SYXaJL/gvTk/dl3pyk7yBFRfeXTsHvTA3dfhoU/LWSq0NKL9nM7WBasJyn6XPSGnLS4RtKXLw5EUg==", - "dev": true, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/@storybook/instrumenter": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/instrumenter/-/instrumenter-8.2.2.tgz", - "integrity": "sha512-refwnHqKHhya45MgqakhMG0jKhTiEIAl0aOwAaQy9+zf9ncMIYQAXRQsSZ2Z188lFWE24wbeHKteb62a5ZfWwQ==", - "dev": true, - "dependencies": { - "@storybook/global": "^5.0.0", - "@vitest/utils": "^1.3.1", - "util": "^0.12.4" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.2" - } - }, - "node_modules/@storybook/preset-react-webpack": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/@storybook/preset-react-webpack/-/preset-react-webpack-8.2.3.tgz", - "integrity": "sha512-i886+vCMGlpFgOAOIg6BxSHgt38MXS6gqNX8Z65KVVIlI6i/9WqEQeHYfukbdGvVZ96cYWmdrnqUieIIkdCdBw==", - "dev": true, - "dependencies": { - "@storybook/core-webpack": "8.2.3", - "@storybook/react": "8.2.3", - "@storybook/react-docgen-typescript-plugin": "1.0.6--canary.9.0c3f3b7.0", - "@types/node": "^18.0.0", - "@types/semver": "^7.3.4", - "find-up": "^5.0.0", - "fs-extra": "^11.1.0", - "magic-string": "^0.30.5", - "react-docgen": "^7.0.0", - "resolve": "^1.22.8", - "semver": "^7.3.7", - "tsconfig-paths": "^4.2.0", - "webpack": "5" - }, - "engines": { - "node": ">=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^8.2.3" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@storybook/preset-react-webpack/node_modules/@types/node": { - "version": "18.19.39", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", - "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@storybook/preset-react-webpack/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@storybook/preset-react-webpack/node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/@storybook/preset-react-webpack/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@storybook/preset-react-webpack/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@storybook/preset-react-webpack/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@storybook/react": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/@storybook/react/-/react-8.2.3.tgz", - "integrity": "sha512-818F6pJWFBiwG0r6DiUVrV+qndwbIso2gtgJoituBgIJO2eIzNmkPNSsckbaR7u+FpE4dWiIIhmDVZSnRwvDlA==", - "dev": true, - "dependencies": { - "@storybook/global": "^5.0.0", - "@storybook/react-dom-shim": "8.2.3", - "@types/escodegen": "^0.0.6", - "@types/estree": "^0.0.51", - "@types/node": "^18.0.0", - "acorn": "^7.4.1", - "acorn-jsx": "^5.3.1", - "acorn-walk": "^7.2.0", - "escodegen": "^2.1.0", - "html-tags": "^3.1.0", - "lodash": "^4.17.21", - "prop-types": "^15.7.2", - "react-element-to-jsx-string": "^15.0.0", - "semver": "^7.3.7", - "ts-dedent": "^2.0.0", - "type-fest": "~2.19", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^8.2.3", - "typescript": ">= 4.2.x" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@storybook/react-docgen-typescript-plugin": { - "version": "1.0.6--canary.9.0c3f3b7.0", - "resolved": "https://registry.npmjs.org/@storybook/react-docgen-typescript-plugin/-/react-docgen-typescript-plugin-1.0.6--canary.9.0c3f3b7.0.tgz", - "integrity": "sha512-KUqXC3oa9JuQ0kZJLBhVdS4lOneKTOopnNBK4tUAgoxWQ3u/IjzdueZjFr7gyBrXMoU6duutk3RQR9u8ZpYJ4Q==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "endent": "^2.0.1", - "find-cache-dir": "^3.3.1", - "flat-cache": "^3.0.4", - "micromatch": "^4.0.2", - "react-docgen-typescript": "^2.2.2", - "tslib": "^2.0.0" - }, - "peerDependencies": { - "typescript": ">= 4.x", - "webpack": ">= 4" - } - }, - "node_modules/@storybook/react-docgen-typescript-plugin/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@storybook/react-docgen-typescript-plugin/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@storybook/react-dom-shim": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-8.2.2.tgz", - "integrity": "sha512-4fb1/yT9WXHzHjs0In6orIEZxga5eXd9UaXEFGudBgowCjDUVP9LabDdKTbGusz20lfaAkATsRG/W+EcSLoh8w==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^8.2.2" - } - }, - "node_modules/@storybook/react-webpack5": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/@storybook/react-webpack5/-/react-webpack5-8.2.3.tgz", - "integrity": "sha512-lcm73r8S5Uy2ENuFDSR07fW+KRSYGNcrF53VItP+rgFZHrOm7gaeebrjSIA6r4tQwdd9218VaqpQGFrKAURS2w==", - "dev": true, - "dependencies": { - "@storybook/builder-webpack5": "8.2.3", - "@storybook/preset-react-webpack": "8.2.3", - "@storybook/react": "8.2.3", - "@types/node": "^18.0.0" - }, - "engines": { - "node": ">=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^8.2.3", - "typescript": ">= 4.2.x" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@storybook/react-webpack5/node_modules/@types/node": { - "version": "18.19.39", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", - "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@storybook/react/node_modules/@storybook/react-dom-shim": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-8.2.3.tgz", - "integrity": "sha512-N8AsM6N1S867GGWt2J2q5oY5ryqxohh3y1HqNtjg+wXf5+RkTD6M2Cgqe6p+JHz81nDKyvvVzP60MvvDhY5VOA==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^8.2.3" - } - }, - "node_modules/@storybook/react/node_modules/@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", - "dev": true - }, - "node_modules/@storybook/react/node_modules/@types/node": { - "version": "18.19.39", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", - "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@storybook/react/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/@storybook/test": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@storybook/test/-/test-8.2.2.tgz", - "integrity": "sha512-X2qAKErjTh1X7XLAZqCMtU0ZK8JuwdKmgiqU0oXWxIDmCX6/Dm9ZIcdMZHs/S+K/UnIByjNlQpTShLVfRUeN1w==", - "dev": true, - "dependencies": { - "@storybook/csf": "0.1.11", - "@storybook/instrumenter": "8.2.2", - "@testing-library/dom": "10.1.0", - "@testing-library/jest-dom": "6.4.5", - "@testing-library/user-event": "14.5.2", - "@vitest/expect": "1.6.0", - "@vitest/spy": "1.6.0", - "util": "^0.12.4" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - }, - "peerDependencies": { - "storybook": "^8.2.2" - } - }, - "node_modules/@svgr/babel-plugin-add-jsx-attribute": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", - "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", - "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", - "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", - "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-svg-dynamic-title": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", - "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-svg-em-dimensions": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", - "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-transform-react-native-svg": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", - "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-transform-svg-component": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", - "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", - "engines": { - "node": ">=12" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-preset": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", - "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", - "dependencies": { - "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", - "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", - "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", - "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", - "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", - "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", - "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", - "@svgr/babel-plugin-transform-svg-component": "8.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/core": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", - "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", - "dependencies": { - "@babel/core": "^7.21.3", - "@svgr/babel-preset": "8.1.0", - "camelcase": "^6.2.0", - "cosmiconfig": "^8.1.3", - "snake-case": "^3.0.4" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/hast-util-to-babel-ast": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", - "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", - "dependencies": { - "@babel/types": "^7.21.3", - "entities": "^4.4.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/hast-util-to-babel-ast/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/@svgr/plugin-jsx": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", - "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", - "dependencies": { - "@babel/core": "^7.21.3", - "@svgr/babel-preset": "8.1.0", - "@svgr/hast-util-to-babel-ast": "8.0.0", - "svg-parser": "^2.0.4" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@svgr/core": "*" - } - }, - "node_modules/@svgr/plugin-svgo": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", - "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", - "dependencies": { - "cosmiconfig": "^8.1.3", - "deepmerge": "^4.3.1", - "svgo": "^3.0.2" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@svgr/core": "*" - } - }, - "node_modules/@svgr/webpack": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", - "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", - "dependencies": { - "@babel/core": "^7.21.3", - "@babel/plugin-transform-react-constant-elements": "^7.21.3", - "@babel/preset-env": "^7.20.2", - "@babel/preset-react": "^7.18.6", - "@babel/preset-typescript": "^7.21.0", - "@svgr/core": "8.1.0", - "@svgr/plugin-jsx": "8.1.0", - "@svgr/plugin-svgo": "8.1.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@swc/core": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.5.7.tgz", - "integrity": "sha512-U4qJRBefIJNJDRCCiVtkfa/hpiZ7w0R6kASea+/KLp+vkus3zcLSB8Ub8SvKgTIxjWpwsKcZlPf5nrv4ls46SQ==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "@swc/counter": "^0.1.2", - "@swc/types": "0.1.7" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/swc" - }, - "optionalDependencies": { - "@swc/core-darwin-arm64": "1.5.7", - "@swc/core-darwin-x64": "1.5.7", - "@swc/core-linux-arm-gnueabihf": "1.5.7", - "@swc/core-linux-arm64-gnu": "1.5.7", - "@swc/core-linux-arm64-musl": "1.5.7", - "@swc/core-linux-x64-gnu": "1.5.7", - "@swc/core-linux-x64-musl": "1.5.7", - "@swc/core-win32-arm64-msvc": "1.5.7", - "@swc/core-win32-ia32-msvc": "1.5.7", - "@swc/core-win32-x64-msvc": "1.5.7" - }, - "peerDependencies": { - "@swc/helpers": "^0.5.0" - }, - "peerDependenciesMeta": { - "@swc/helpers": { - "optional": true - } - } - }, - "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.5.7.tgz", - "integrity": "sha512-tp43WfJLCsKLQKBmjmY/0vv1slVywR5Q4qKjF5OIY8QijaEW7/8VwPyUyVoJZEnDgv9jKtUTG5PzqtIYPZGnyg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/counter": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", - "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", - "dev": true - }, - "node_modules/@swc/types": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.7.tgz", - "integrity": "sha512-scHWahbHF0eyj3JsxG9CFJgFdFNaVQCNAimBlT6PzS3n/HptxqREjsm4OH6AN3lYcffZYSPxXW8ua2BEHp0lJQ==", - "dev": true, - "dependencies": { - "@swc/counter": "^0.1.3" - } - }, - "node_modules/@testing-library/dom": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.1.0.tgz", - "integrity": "sha512-wdsYKy5zupPyLCW2Je5DLHSxSfbIp6h80WoHOQc+RPtmPGA52O9x5MJEkv92Sjonpq+poOAtUKhh1kBGAXBrNA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.3.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@testing-library/dom/node_modules/aria-query": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", - "dev": true, - "dependencies": { - "dequal": "^2.0.3" - } - }, - "node_modules/@testing-library/jest-dom": { - "version": "6.4.5", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.4.5.tgz", - "integrity": "sha512-AguB9yvTXmCnySBP1lWjfNNUwpbElsaQ567lt2VdGqAdHtpieLgjmcVyv1q7PMIvLbgpDdkWV5Ydv3FEejyp2A==", - "dev": true, - "dependencies": { - "@adobe/css-tools": "^4.3.2", - "@babel/runtime": "^7.9.2", - "aria-query": "^5.0.0", - "chalk": "^3.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.6.3", - "lodash": "^4.17.21", - "redent": "^3.0.0" - }, - "engines": { - "node": ">=14", - "npm": ">=6", - "yarn": ">=1" - }, - "peerDependencies": { - "@jest/globals": ">= 28", - "@types/bun": "latest", - "@types/jest": ">= 28", - "jest": ">= 28", - "vitest": ">= 0.32" - }, - "peerDependenciesMeta": { - "@jest/globals": { - "optional": true - }, - "@types/bun": { - "optional": true - }, - "@types/jest": { - "optional": true - }, - "jest": { - "optional": true - }, - "vitest": { - "optional": true - } - } - }, - "node_modules/@testing-library/jest-dom/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", - "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", - "dev": true - }, - "node_modules/@testing-library/jest-dom/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/user-event": { - "version": "14.5.2", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.2.tgz", - "integrity": "sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==", - "dev": true, - "engines": { - "node": ">=12", - "npm": ">=6" - }, - "peerDependencies": { - "@testing-library/dom": ">=7.21.4" - } - }, - "node_modules/@trysound/sax": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", - "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/@types/aria-query": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", - "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", - "dev": true - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", - "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.7" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", - "dev": true, - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/cross-spawn": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/@types/cross-spawn/-/cross-spawn-6.0.6.tgz", - "integrity": "sha512-fXRhhUkG4H3TQk5dBhQ7m/JDdSNHKwR2BBia62lhwEIq9xGiQKLxd6LymNhn47SjXhsUEPmxi+PKw2OkW4LLjA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/doctrine": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/@types/doctrine/-/doctrine-0.0.9.tgz", - "integrity": "sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==", - "dev": true - }, - "node_modules/@types/emscripten": { - "version": "1.39.13", - "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.39.13.tgz", - "integrity": "sha512-cFq+fO/isvhvmuP/+Sl4K4jtU6E23DoivtbO4r50e3odaxAiVdbfSYRDdJ4gCdxx+3aRjhphS5ZMwIH4hFy/Cw==", - "dev": true - }, - "node_modules/@types/escodegen": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@types/escodegen/-/escodegen-0.0.6.tgz", - "integrity": "sha512-AjwI4MvWx3HAOaZqYsjKWyEObT9lcVV0Y0V8nXo6cXzN8ZiMxVhf6F3d/UNvXVGKrEzL/Dluc5p+y9GkzlTWig==", - "dev": true - }, - "node_modules/@types/eslint": { - "version": "8.56.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", - "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", - "dev": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dev": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true - }, - "node_modules/@types/express": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", - "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", - "dev": true, - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.19.5", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", - "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "dev": true, - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@types/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", - "dev": true - }, - "node_modules/@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "node_modules/@types/lodash": { - "version": "4.17.6", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.6.tgz", - "integrity": "sha512-OpXEVoCKSS3lQqjx9GGGOapBeuW5eUboYHRlHP9urXPX25IKZ6AnP5ZRxtVf63iieUbsHxLn8NQ5Nlftc6yzAA==", - "dev": true - }, - "node_modules/@types/mdx": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", - "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", - "dev": true - }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true - }, - "node_modules/@types/node": { - "version": "20.14.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", - "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/parse-json": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" - }, - "node_modules/@types/prop-types": { - "version": "15.7.12", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "dev": true - }, - "node_modules/@types/qs": { - "version": "6.9.15", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", - "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", - "dev": true - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true - }, - "node_modules/@types/react": { - "version": "18.3.3", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", - "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", - "dev": true, - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", - "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", - "dev": true, - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/resolve": { - "version": "1.20.6", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz", - "integrity": "sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==", - "dev": true - }, - "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true - }, - "node_modules/@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", - "dev": true, - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.7", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", - "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", - "dev": true, - "dependencies": { - "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "*" - } - }, - "node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==", - "dev": true - }, - "node_modules/@types/uuid": { - "version": "9.0.8", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", - "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.16.0.tgz", - "integrity": "sha512-py1miT6iQpJcs1BiJjm54AMzeuMPBSPuKPlnT8HlfudbcS5rYeX5jajpLf3mrdRh9dA/Ec2FVUY0ifeVNDIhZw==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.16.0", - "@typescript-eslint/type-utils": "7.16.0", - "@typescript-eslint/utils": "7.16.0", - "@typescript-eslint/visitor-keys": "7.16.0", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.16.0.tgz", - "integrity": "sha512-j0fuUswUjDHfqV/UdW6mLtOQQseORqfdmoBNDFOqs9rvNVR2e+cmu6zJu/Ku4SDuqiJko6YnhwcL8x45r8Oqxg==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "7.16.0", - "@typescript-eslint/utils": "7.16.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.0.tgz", - "integrity": "sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.16.0", - "@typescript-eslint/types": "7.16.0", - "@typescript-eslint/typescript-estree": "7.16.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@typescript-eslint/parser": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.16.0.tgz", - "integrity": "sha512-ar9E+k7CU8rWi2e5ErzQiC93KKEFAXA2Kky0scAlPcxYblLt8+XZuHUZwlyfXILyQa95P6lQg+eZgh/dDs3+Vw==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "7.16.0", - "@typescript-eslint/types": "7.16.0", - "@typescript-eslint/typescript-estree": "7.16.0", - "@typescript-eslint/visitor-keys": "7.16.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.16.0.tgz", - "integrity": "sha512-8gVv3kW6n01Q6TrI1cmTZ9YMFi3ucDT7i7aI5lEikk2ebk1AEjrwX8MDTdaX5D7fPXMBLvnsaa0IFTAu+jcfOw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.16.0", - "@typescript-eslint/visitor-keys": "7.16.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.16.0.tgz", - "integrity": "sha512-fecuH15Y+TzlUutvUl9Cc2XJxqdLr7+93SQIbcZfd4XRGGKoxyljK27b+kxKamjRkU7FYC6RrbSCg0ALcZn/xw==", - "dev": true, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.16.0.tgz", - "integrity": "sha512-a5NTvk51ZndFuOLCh5OaJBELYc2O3Zqxfl3Js78VFE1zE46J2AaVuW+rEbVkQznjkmlzWsUI15BG5tQMixzZLw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.16.0", - "@typescript-eslint/visitor-keys": "7.16.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", - "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", - "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", - "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", - "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", - "dev": 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.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", - "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.16.0.tgz", - "integrity": "sha512-rMo01uPy9C7XxG7AFsxa8zLnWXTF8N3PYclekWSrurvhwiw1eW88mrKiAYe6s53AUY57nTRz8dJsuuXdkAhzCg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.16.0", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "node_modules/@vitest/expect": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", - "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", - "dev": true, - "dependencies": { - "@vitest/spy": "1.6.0", - "@vitest/utils": "1.6.0", - "chai": "^4.3.10" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", - "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", - "dev": true, - "dependencies": { - "tinyspy": "^2.2.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", - "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", - "dev": true, - "dependencies": { - "diff-sequences": "^29.6.3", - "estree-walker": "^3.0.3", - "loupe": "^2.3.7", - "pretty-format": "^29.7.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@vitest/utils/node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@vitest/utils/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", - "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", - "dev": true, - "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", - "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", - "dev": true, - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", - "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.12.1" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", - "dev": true, - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", - "dev": true, - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", - "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-opt": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1", - "@webassemblyjs/wast-printer": "1.12.1" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", - "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", - "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", - "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", - "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "node_modules/@yarnpkg/fslib": { - "version": "2.10.3", - "resolved": "https://registry.npmjs.org/@yarnpkg/fslib/-/fslib-2.10.3.tgz", - "integrity": "sha512-41H+Ga78xT9sHvWLlFOZLIhtU6mTGZ20pZ29EiZa97vnxdohJD2AF42rCoAoWfqUz486xY6fhjMH+DYEM9r14A==", - "dev": true, - "dependencies": { - "@yarnpkg/libzip": "^2.3.0", - "tslib": "^1.13.0" - }, - "engines": { - "node": ">=12 <14 || 14.2 - 14.9 || >14.10.0" - } - }, - "node_modules/@yarnpkg/fslib/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/@yarnpkg/libzip": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@yarnpkg/libzip/-/libzip-2.3.0.tgz", - "integrity": "sha512-6xm38yGVIa6mKm/DUCF2zFFJhERh/QWp1ufm4cNUvxsONBmfPg8uZ9pZBdOmF6qFGr/HlT6ABBkCSx/dlEtvWg==", - "dev": true, - "dependencies": { - "@types/emscripten": "^1.39.6", - "tslib": "^1.13.0" - }, - "engines": { - "node": ">=12 <14 || 14.2 - 14.9 || >14.10.0" - } - }, - "node_modules/@yarnpkg/libzip/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-import-attributes": { - "version": "1.9.5", - "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", - "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", - "dev": true, - "peerDependencies": { - "acorn": "^8" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", - "dev": true, - "engines": [ - "node >= 0.8.0" - ], - "bin": { - "ansi-html": "bin/ansi-html" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "dev": true, - "dependencies": { - "deep-equal": "^2.0.5" - } - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true - }, - "node_modules/array-includes": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", - "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array.prototype.findlast": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", - "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", - "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.toreversed": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", - "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - } - }, - "node_modules/array.prototype.tosorted": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", - "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", - "es-errors": "^1.3.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/ast-types": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", - "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", - "dev": true, - "dependencies": { - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ast-types-flow": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", - "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", - "dev": true - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dev": true, - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/axe-core": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.9.1.tgz", - "integrity": "sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/axobject-query": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", - "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", - "dev": true, - "dependencies": { - "deep-equal": "^2.0.5" - } - }, - "node_modules/babel-core": { - "version": "7.0.0-bridge.0", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", - "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", - "dev": true, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-macros": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", - "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", - "dependencies": { - "@babel/runtime": "^7.12.5", - "cosmiconfig": "^7.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">=10", - "npm": ">=6" - } - }, - "node_modules/babel-plugin-macros/node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.11", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", - "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", - "dependencies": { - "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.6.2", - "semver": "^6.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz", - "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.1", - "core-js-compat": "^3.36.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", - "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", - "dev": true, - "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.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" - }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-assert": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/browser-assert/-/browser-assert-1.2.1.tgz", - "integrity": "sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ==", - "dev": true - }, - "node_modules/browserslist": { - "version": "4.23.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", - "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001640", - "electron-to-chromium": "^1.4.820", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.1.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", - "dev": true, - "dependencies": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001642", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz", - "integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/case-sensitive-paths-webpack-plugin": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", - "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/chai": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", - "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", - "dev": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.0.8" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/chromatic": { - "version": "11.5.5", - "resolved": "https://registry.npmjs.org/chromatic/-/chromatic-11.5.5.tgz", - "integrity": "sha512-YS0GJwegF0vpMbwZE68/xJlI4SlUGMqI78V2ATAF19YwTHaq8jGP1CPQGKUSlgWUhzPtyu3ELy6Dvv/owYljAg==", - "dev": true, - "bin": { - "chroma": "dist/bin.js", - "chromatic": "dist/bin.js", - "chromatic-cli": "dist/bin.js" - }, - "peerDependencies": { - "@chromatic-com/cypress": "^0.*.* || ^1.0.0", - "@chromatic-com/playwright": "^0.*.* || ^1.0.0" - }, - "peerDependenciesMeta": { - "@chromatic-com/cypress": { - "optional": true - }, - "@chromatic-com/playwright": { - "optional": true - } - } - }, - "node_modules/chrome-trace-event": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", - "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", - "dev": true, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/citty": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", - "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", - "dev": true, - "dependencies": { - "consola": "^3.2.3" - } - }, - "node_modules/cjs-module-lexer": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz", - "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==", - "dev": true - }, - "node_modules/clean-css": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", - "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", - "dev": true, - "dependencies": { - "source-map": "~0.6.0" - }, - "engines": { - "node": ">= 10.0" - } - }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true - }, - "node_modules/compare-versions": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", - "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/confbox": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz", - "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==", - "dev": true - }, - "node_modules/consola": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", - "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==", - "dev": true, - "engines": { - "node": "^14.18.0 || >=16.10.0" - } - }, - "node_modules/constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", - "dev": true - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" - }, - "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true - }, - "node_modules/core-js-compat": { - "version": "3.37.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", - "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", - "dependencies": { - "browserslist": "^4.23.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dependencies": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/crypto-random-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", - "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", - "dev": true, - "dependencies": { - "type-fest": "^1.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/crypto-random-string/node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/css-loader": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", - "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", - "dev": true, - "dependencies": { - "icss-utils": "^5.1.0", - "postcss": "^8.4.33", - "postcss-modules-extract-imports": "^3.1.0", - "postcss-modules-local-by-default": "^4.0.5", - "postcss-modules-scope": "^3.2.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "@rspack/core": "0.x || 1.x", - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - }, - "webpack": { - "optional": true - } - } - }, - "node_modules/css-select": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dependencies": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" - } - }, - "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", - "dev": true - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/csso": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", - "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", - "dependencies": { - "css-tree": "~2.2.0" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/csso/node_modules/css-tree": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", - "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", - "dependencies": { - "mdn-data": "2.0.28", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/csso/node_modules/mdn-data": { - "version": "2.0.28", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", - "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==" - }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" - }, - "node_modules/damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", - "dev": true - }, - "node_modules/data-view-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", - "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", - "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", - "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "node_modules/deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", - "dev": true, - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/deep-equal": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", - "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.5", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.2", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.2", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/deep-equal/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "dev": true, - "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/defu": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", - "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", - "dev": true - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-indent": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", - "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/dom-accessibility-api": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", - "dev": true - }, - "node_modules/dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", - "dev": true, - "dependencies": { - "utila": "~0.4" - } - }, - "node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "dev": true, - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "dev": true, - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true - }, - "node_modules/electron-to-chromium": { - "version": "1.4.827", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.827.tgz", - "integrity": "sha512-VY+J0e4SFcNfQy19MEoMdaIcZLmDCprqvBtkii1WTCTQHpRvf5N8+3kTYCgL/PcntvwQvmMJWTuDPsq+IlhWKQ==" - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/endent": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/endent/-/endent-2.1.0.tgz", - "integrity": "sha512-r8VyPX7XL8U01Xgnb1CjZ3XV+z90cXIJ9JPE/R9SEC9vpw2P6CfsRPJmp20DppC5N7ZAMCmjYkJIa744Iyg96w==", - "dev": true, - "dependencies": { - "dedent": "^0.7.0", - "fast-json-parse": "^1.0.3", - "objectorarray": "^1.0.5" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", - "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/envinfo": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", - "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", - "dev": true, - "bin": { - "envinfo": "dist/cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.23.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", - "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "data-view-buffer": "^1.0.1", - "data-view-byte-length": "^1.0.1", - "data-view-byte-offset": "^1.0.0", - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-set-tostringtag": "^2.0.3", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "hasown": "^2.0.2", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.1", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.2", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.9", - "string.prototype.trimend": "^1.0.8", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.6", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.15" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-get-iterator/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/es-iterator-helpers": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", - "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", - "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.3", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.7", - "iterator.prototype": "^1.1.2", - "safe-array-concat": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-module-lexer": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", - "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", - "dev": true - }, - "node_modules/es-object-atoms": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", - "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, - "node_modules/esbuild-register": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.5.0.tgz", - "integrity": "sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==", - "dev": true, - "dependencies": { - "debug": "^4.3.4" - }, - "peerDependencies": { - "esbuild": ">=0.12 <1" - } - }, - "node_modules/esbuild-register/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/esbuild-register/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/escodegen": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", - "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", - "dev": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint": { - "version": "9.7.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.7.0.tgz", - "integrity": "sha512-FzJ9D/0nGiCGBf8UXO/IGLTgLVzIxze1zpfA8Ton2mjLovXdAPlYDv+MQDcqj3TmrhAGYfOpz9RfR+ent0AgAw==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.11.0", - "@eslint/config-array": "^0.17.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.7.0", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.3.0", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.0.2", - "eslint-visitor-keys": "^4.0.0", - "espree": "^10.1.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "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" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - } - }, - "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/eslint-import-resolver-typescript": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", - "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", - "dev": true, - "dependencies": { - "debug": "^4.3.4", - "enhanced-resolve": "^5.12.0", - "eslint-module-utils": "^2.7.4", - "fast-glob": "^3.3.1", - "get-tsconfig": "^4.5.0", - "is-core-module": "^2.11.0", - "is-glob": "^4.0.3" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" - }, - "peerDependencies": { - "eslint": "*", - "eslint-plugin-import": "*" - } - }, - "node_modules/eslint-import-resolver-typescript/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/eslint-import-resolver-typescript/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/eslint-module-utils": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", - "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", - "dev": true, - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/eslint-plugin-import": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", - "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", - "object.values": "^1.1.7", - "semver": "^6.3.1", - "tsconfig-paths": "^3.15.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/eslint-plugin-import/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-import/node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.9.0.tgz", - "integrity": "sha512-nOFOCaJG2pYqORjK19lqPqxMO/JpvdCZdPtNdxY3kvom3jTvkAbOvQvD8wuD0G8BYR0IGAGYDlzqWJOh/ybn2g==", - "dev": true, - "dependencies": { - "aria-query": "~5.1.3", - "array-includes": "^3.1.8", - "array.prototype.flatmap": "^1.3.2", - "ast-types-flow": "^0.0.8", - "axe-core": "^4.9.1", - "axobject-query": "~3.1.1", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "es-iterator-helpers": "^1.0.19", - "hasown": "^2.0.2", - "jsx-ast-utils": "^3.3.5", - "language-tags": "^1.0.9", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "safe-regex-test": "^1.0.3", - "string.prototype.includes": "^2.0.0" - }, - "engines": { - "node": ">=4.0" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", - "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", - "dev": true, - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.8.6" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "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 - } - } - }, - "node_modules/eslint-plugin-react": { - "version": "7.34.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.4.tgz", - "integrity": "sha512-Np+jo9bUwJNxCsT12pXtrGhJgT3T44T1sHhn1Ssr42XFn8TES0267wPGo5nNrMHi8qkyimDAX2BUmkf9pSaVzA==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.8", - "array.prototype.findlast": "^1.2.5", - "array.prototype.flatmap": "^1.3.2", - "array.prototype.toreversed": "^1.1.2", - "array.prototype.tosorted": "^1.1.4", - "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.19", - "estraverse": "^5.3.0", - "hasown": "^2.0.2", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.8", - "object.fromentries": "^2.0.8", - "object.values": "^1.2.0", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.5", - "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.11", - "string.prototype.repeat": "^1.0.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", - "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/eslint-plugin-react/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-react/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint-plugin-react/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/eslint-plugin-react/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-storybook": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-0.8.0.tgz", - "integrity": "sha512-CZeVO5EzmPY7qghO2t64oaFM+8FTaD4uzOEjHKp516exyTKo+skKAL9GI3QALS2BXhyALJjNtwbmr1XinGE8bA==", - "dev": true, - "dependencies": { - "@storybook/csf": "^0.0.1", - "@typescript-eslint/utils": "^5.62.0", - "requireindex": "^1.2.0", - "ts-dedent": "^2.2.0" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "eslint": ">=6" - } - }, - "node_modules/eslint-plugin-storybook/node_modules/@storybook/csf": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.0.1.tgz", - "integrity": "sha512-USTLkZze5gkel8MYCujSRBVIrUQ3YPBrLOx7GNk/0wttvVtlzWXAq9eLbQ4p/NicGxP+3T7KPEMVV//g+yubpw==", - "dev": true, - "dependencies": { - "lodash": "^4.17.15" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", - "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", - "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/espree": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", - "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", - "dev": true, - "dependencies": { - "acorn": "^8.12.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", - "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", - "dev": true, - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.2", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.6.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" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-json-parse": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz", - "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==", - "dev": true - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fast-uri": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", - "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fd-package-json": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fd-package-json/-/fd-package-json-1.2.0.tgz", - "integrity": "sha512-45LSPmWf+gC5tdCQMNH4s9Sr00bIkiD9aN7dc5hqkrEw1geRYyDQS1v1oMHAW3ysfxfndqGsrDREHHjNNbKUfA==", - "dev": true, - "dependencies": { - "walk-up-path": "^3.0.1" - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/file-entry-cache/node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/file-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", - "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", - "dev": true, - "dependencies": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "node_modules/filesize": { - "version": "10.1.4", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.1.4.tgz", - "integrity": "sha512-ryBwPIIeErmxgPnm6cbESAzXjuEFubs+yKYLBZvg3CaiNcmkJChoOGcBSrZ6IwkMwPABwPpVXE6IlNdGJJrvEg==", - "dev": true, - "engines": { - "node": ">= 10.4.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dev": true, - "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" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, - "node_modules/find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flat-cache/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/flat-cache/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/flat-cache/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/flow-parser": { - "version": "0.239.1", - "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.239.1.tgz", - "integrity": "sha512-topOrETNxJ6T2gAnQiWqAlzGPj8uI2wtmNOlDIMNB+qyvGJZ6R++STbUOTAYmvPhOMz2gXnXPH0hOvURYmrBow==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fs-minipass/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/fs-monkey": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", - "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", - "dev": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-tsconfig": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz", - "integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==", - "dev": true, - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "node_modules/giget": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/giget/-/giget-1.2.3.tgz", - "integrity": "sha512-8EHPljDvs7qKykr6uw8b+lqLiUc/vUg+KVTI0uND4s63TdsZM2Xus3mflvF0DDG9SiM4RlCkFGL+7aAjRmV7KA==", - "dev": true, - "dependencies": { - "citty": "^0.1.6", - "consola": "^3.2.3", - "defu": "^6.1.4", - "node-fetch-native": "^1.6.3", - "nypm": "^0.3.8", - "ohash": "^1.1.3", - "pathe": "^1.1.2", - "tar": "^6.2.0" - }, - "bin": { - "giget": "dist/cli.mjs" - } - }, - "node_modules/github-slugger": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", - "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", - "dev": true - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "node_modules/globals": { - "version": "15.8.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.8.0.tgz", - "integrity": "sha512-VZAJ4cewHTExBWDHR6yptdIBlx9YSSZuwojj9Nt5mBRXQzrKakDsVKQ1J63sklLvzAJm0X5+RpO4i3Y2hcOnFw==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hast-util-heading-rank": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-heading-rank/-/hast-util-heading-rank-3.0.0.tgz", - "integrity": "sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==", - "dev": true, - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-is-element": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", - "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", - "dev": true, - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-to-string": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.0.tgz", - "integrity": "sha512-OGkAxX1Ua3cbcW6EJ5pT/tslVb90uViVkcJ4ZZIMW/R33DX/AkcJcRrPebPwJkHYwlDHXz4aIwvAAaAdtrACFA==", - "dev": true, - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "dependencies": { - "react-is": "^16.7.0" - } - }, - "node_modules/html-entities": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", - "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/mdevils" - }, - { - "type": "patreon", - "url": "https://patreon.com/mdevils" - } - ] - }, - "node_modules/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", - "dev": true, - "dependencies": { - "camel-case": "^4.1.2", - "clean-css": "^5.2.2", - "commander": "^8.3.0", - "he": "^1.2.0", - "param-case": "^3.0.4", - "relateurl": "^0.2.7", - "terser": "^5.10.0" - }, - "bin": { - "html-minifier-terser": "cli.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/html-minifier-terser/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/html-tags": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", - "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/html-webpack-plugin": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", - "integrity": "sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==", - "dev": true, - "dependencies": { - "@types/html-minifier-terser": "^6.0.0", - "html-minifier-terser": "^6.0.2", - "lodash": "^4.17.21", - "pretty-error": "^4.0.0", - "tapable": "^2.0.0" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/html-webpack-plugin" - }, - "peerDependencies": { - "@rspack/core": "0.x || 1.x", - "webpack": "^5.20.0" - }, - "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - }, - "webpack": { - "optional": true - } - } - }, - "node_modules/htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "engines": { - "node": ">=4" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-absolute-url": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-4.0.1.tgz", - "integrity": "sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" - }, - "node_modules/is-async-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", - "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", - "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-view": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", - "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", - "dev": true, - "dependencies": { - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-finalizationregistry": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", - "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", - "dev": true, - "dependencies": { - "which-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", - "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/iterator.prototype": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", - "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "reflect.getprototypeof": "^1.0.4", - "set-function-name": "^2.0.1" - } - }, - "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jscodeshift": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.15.2.tgz", - "integrity": "sha512-FquR7Okgmc4Sd0aEDwqho3rEiKR3BdvuG9jfdHjLJ6JQoWSMpavug3AoIfnfWhxFlf+5pzQh8qjqz0DWFrNQzA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.23.0", - "@babel/parser": "^7.23.0", - "@babel/plugin-transform-class-properties": "^7.22.5", - "@babel/plugin-transform-modules-commonjs": "^7.23.0", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.11", - "@babel/plugin-transform-optional-chaining": "^7.23.0", - "@babel/plugin-transform-private-methods": "^7.22.5", - "@babel/preset-flow": "^7.22.15", - "@babel/preset-typescript": "^7.23.0", - "@babel/register": "^7.22.15", - "babel-core": "^7.0.0-bridge.0", - "chalk": "^4.1.2", - "flow-parser": "0.*", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.4", - "neo-async": "^2.5.0", - "node-dir": "^0.1.17", - "recast": "^0.23.3", - "temp": "^0.8.4", - "write-file-atomic": "^2.3.0" - }, - "bin": { - "jscodeshift": "bin/jscodeshift.js" - }, - "peerDependencies": { - "@babel/preset-env": "^7.1.6" - }, - "peerDependenciesMeta": { - "@babel/preset-env": { - "optional": true - } - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsx-ast-utils": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", - "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/language-subtag-registry": { - "version": "0.3.23", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", - "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", - "dev": true - }, - "node_modules/language-tags": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", - "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", - "dev": true, - "dependencies": { - "language-subtag-registry": "^0.3.20" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" - }, - "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "dev": true, - "engines": { - "node": ">=6.11.5" - } - }, - "node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.1" - } - }, - "node_modules/lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dependencies": { - "tslib": "^2.0.3" - } - }, - "node_modules/lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", - "dev": true, - "bin": { - "lz-string": "bin/bin.js" - } - }, - "node_modules/magic-string": { - "version": "0.30.10", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", - "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/map-or-similar": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz", - "integrity": "sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==", - "dev": true - }, - "node_modules/markdown-to-jsx": { - "version": "7.4.7", - "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.4.7.tgz", - "integrity": "sha512-0+ls1IQZdU6cwM1yu0ZjjiVWYtkbExSyUIFU2ZeDIFuZM1W42Mh4OlJ4nb4apX4H8smxDHRdFaoIVJGwfv5hkg==", - "dev": true, - "engines": { - "node": ">= 10" - }, - "peerDependencies": { - "react": ">= 0.14.0" - } - }, - "node_modules/mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memoizerific": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/memoizerific/-/memoizerific-1.11.3.tgz", - "integrity": "sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==", - "dev": true, - "dependencies": { - "map-or-similar": "^1.5.0" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", - "dev": true, - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minizlib/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mlly": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.1.tgz", - "integrity": "sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==", - "dev": true, - "dependencies": { - "acorn": "^8.11.3", - "pathe": "^1.1.2", - "pkg-types": "^1.1.1", - "ufo": "^1.5.3" - } - }, - "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/mylas": { - "version": "2.1.13", - "resolved": "https://registry.npmjs.org/mylas/-/mylas-2.1.13.tgz", - "integrity": "sha512-+MrqnJRtxdF+xngFfUUkIMQrUUL0KsxbADUkn23Z/4ibGg192Q+z+CQyiYwvWTsYjJygmMR8+w3ZDa98Zh6ESg==", - "dev": true, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/raouldeheer" - } - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node_modules/no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dependencies": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - } - }, - "node_modules/node-abort-controller": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", - "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", - "dev": true - }, - "node_modules/node-dir": { - "version": "0.1.17", - "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", - "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", - "dev": true, - "dependencies": { - "minimatch": "^3.0.2" - }, - "engines": { - "node": ">= 0.10.5" - } - }, - "node_modules/node-dir/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/node-dir/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/node-fetch-native": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.4.tgz", - "integrity": "sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/nypm": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.3.9.tgz", - "integrity": "sha512-BI2SdqqTHg2d4wJh8P9A1W+bslg33vOE9IZDY6eR2QC+Pu1iNBVZUqczrd43rJb+fMzHU7ltAYKsEFY/kHMFcw==", - "dev": true, - "dependencies": { - "citty": "^0.1.6", - "consola": "^3.2.3", - "execa": "^8.0.1", - "pathe": "^1.1.2", - "pkg-types": "^1.1.1", - "ufo": "^1.5.3" - }, - "bin": { - "nypm": "dist/cli.mjs" - }, - "engines": { - "node": "^14.16.0 || >=16.10.0" - } - }, - "node_modules/nypm/node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/nypm/node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", - "dev": true, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nypm/node_modules/human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", - "dev": true, - "engines": { - "node": ">=16.17.0" - } - }, - "node_modules/nypm/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nypm/node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nypm/node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", - "dev": true, - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nypm/node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dev": true, - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nypm/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nypm/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/nypm/node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-is": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", - "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", - "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", - "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.groupby": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", - "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.values": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", - "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/objectorarray": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/objectorarray/-/objectorarray-1.0.5.tgz", - "integrity": "sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg==", - "dev": true - }, - "node_modules/ohash": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/ohash/-/ohash-1.1.3.tgz", - "integrity": "sha512-zuHHiGTYTA1sYJ/wZN+t5HKZaH23i4yI1HMwbuXm24Nid7Dv0KcuRlKoNKS9UNfAVSBlnGLcuQrnOKWOZoEGaw==", - "dev": true - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/param-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", - "dev": true, - "dependencies": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/pascal-case": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", - "dev": true, - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/path-browserify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", - "dev": true - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/pathe": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", - "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", - "dev": true - }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-types": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.1.3.tgz", - "integrity": "sha512-+JrgthZG6m3ckicaOB74TwQ+tBWsFl3qVQg7mN8ulwSOElJ7gBhKzj2VkCPnZ4NlF6kEquYU+RIYNVAvzd54UA==", - "dev": true, - "dependencies": { - "confbox": "^0.1.7", - "mlly": "^1.7.1", - "pathe": "^1.1.2" - } - }, - "node_modules/plimit-lit": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/plimit-lit/-/plimit-lit-1.6.1.tgz", - "integrity": "sha512-B7+VDyb8Tl6oMJT9oSO2CW8XC/T4UcJGrwOVoNGwOQsQYhlpfajmrMj5xeejqaASq3V/EqThyOeATEOMuSEXiA==", - "dev": true, - "dependencies": { - "queue-lit": "^1.5.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/polished": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz", - "integrity": "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.17.8" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/postcss": { - "version": "8.4.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", - "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.1", - "source-map-js": "^1.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-modules-extract-imports": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", - "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-local-by-default": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", - "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", - "dev": true, - "dependencies": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-scope": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", - "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "dev": true, - "dependencies": { - "icss-utils": "^5.0.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz", - "integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", - "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/pretty-error": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", - "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", - "dev": true, - "dependencies": { - "lodash": "^4.17.20", - "renderkid": "^3.0.0" - } - }, - "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/pretty-format/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "dev": true, - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-addr/node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue-lit": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/queue-lit/-/queue-lit-1.5.2.tgz", - "integrity": "sha512-tLc36IOPeMAubu8BkW8YDBV+WyIgKlYU7zUNs0J5Vk9skSZ4JfGlPOqplP0aHdfv7HL0B2Pg6nwiq60Qc6M2Hw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "dev": true, - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/raw-body/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-colorful": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz", - "integrity": "sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==", - "dev": true, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/react-confetti": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/react-confetti/-/react-confetti-6.1.0.tgz", - "integrity": "sha512-7Ypx4vz0+g8ECVxr88W9zhcQpbeujJAVqL14ZnXJ3I23mOI9/oBVTQ3dkJhUmB0D6XOtCZEM6N0Gm9PMngkORw==", - "dev": true, - "dependencies": { - "tween-functions": "^1.2.0" - }, - "engines": { - "node": ">=10.18" - }, - "peerDependencies": { - "react": "^16.3.0 || ^17.0.1 || ^18.0.0" - } - }, - "node_modules/react-docgen": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-7.0.3.tgz", - "integrity": "sha512-i8aF1nyKInZnANZ4uZrH49qn1paRgBZ7wZiCNBMnenlPzEv0mRl+ShpTVEI6wZNl8sSc79xZkivtgLKQArcanQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.18.9", - "@babel/traverse": "^7.18.9", - "@babel/types": "^7.18.9", - "@types/babel__core": "^7.18.0", - "@types/babel__traverse": "^7.18.0", - "@types/doctrine": "^0.0.9", - "@types/resolve": "^1.20.2", - "doctrine": "^3.0.0", - "resolve": "^1.22.1", - "strip-indent": "^4.0.0" - }, - "engines": { - "node": ">=16.14.0" - } - }, - "node_modules/react-docgen-typescript": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-2.2.2.tgz", - "integrity": "sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==", - "dev": true, - "peerDependencies": { - "typescript": ">= 4.3.x" - } - }, - "node_modules/react-docgen/node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, - "node_modules/react-element-to-jsx-string": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/react-element-to-jsx-string/-/react-element-to-jsx-string-15.0.0.tgz", - "integrity": "sha512-UDg4lXB6BzlobN60P8fHWVPX3Kyw8ORrTeBtClmIlGdkOOE+GYQSFvmEU5iLLpwp/6v42DINwNcwOhOLfQ//FQ==", - "dev": true, - "dependencies": { - "@base2/pretty-print-object": "1.0.1", - "is-plain-object": "5.0.0", - "react-is": "18.1.0" - }, - "peerDependencies": { - "react": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0", - "react-dom": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0" - } - }, - "node_modules/react-element-to-jsx-string/node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-element-to-jsx-string/node_modules/react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - }, - "node_modules/react-inspector": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-6.0.2.tgz", - "integrity": "sha512-x+b7LxhmHXjHoU/VrFAzw5iutsILRoYyDq97EDYdFpPLcvqtEzk4ZSZSQjnFPbr5T57tLXnHcqFYoN1pI6u8uQ==", - "dev": true, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/react-router": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.24.1.tgz", - "integrity": "sha512-PTXFXGK2pyXpHzVo3rR9H7ip4lSPZZc0bHG5CARmj65fTT6qG7sTngmb6lcYu1gf3y/8KxORoy9yn59pGpCnpg==", - "dependencies": { - "@remix-run/router": "1.17.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8" - } - }, - "node_modules/react-router-dom": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.24.1.tgz", - "integrity": "sha512-U19KtXqooqw967Vw0Qcn5cOvrX5Ejo9ORmOtJMzYWtCT4/WOfFLIZGGsVLxcd9UkBO0mSTZtXqhZBsWlHr7+Sg==", - "dependencies": { - "@remix-run/router": "1.17.1", - "react-router": "6.24.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/recast": { - "version": "0.23.9", - "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.9.tgz", - "integrity": "sha512-Hx/BGIbwj+Des3+xy5uAtAbdCyqK9y9wbBcDFDYanLS9JnMqf7OeF87HQwUimE87OEc72mr6tkKUKMBBL+hF9Q==", - "dev": true, - "dependencies": { - "ast-types": "^0.16.1", - "esprima": "~4.0.0", - "source-map": "~0.6.1", - "tiny-invariant": "^1.3.3", - "tslib": "^2.0.1" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dev": true, - "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/redent/node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", - "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.1", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", - "which-builtin-type": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", - "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - }, - "node_modules/regenerator-transform": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", - "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpu-core": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", - "dependencies": { - "@babel/regjsgen": "^0.8.0", - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", - "dependencies": { - "jsesc": "~0.5.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "bin": { - "jsesc": "bin/jsesc" - } - }, - "node_modules/rehype-external-links": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/rehype-external-links/-/rehype-external-links-3.0.0.tgz", - "integrity": "sha512-yp+e5N9V3C6bwBeAC4n796kc86M4gJCdlVhiMTxIrJG5UHDMh+PJANf9heqORJbt1nrCbDwIlAZKjANIaVBbvw==", - "dev": true, - "dependencies": { - "@types/hast": "^3.0.0", - "@ungap/structured-clone": "^1.0.0", - "hast-util-is-element": "^3.0.0", - "is-absolute-url": "^4.0.0", - "space-separated-tokens": "^2.0.0", - "unist-util-visit": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/rehype-slug": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/rehype-slug/-/rehype-slug-6.0.0.tgz", - "integrity": "sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==", - "dev": true, - "dependencies": { - "@types/hast": "^3.0.0", - "github-slugger": "^2.0.0", - "hast-util-heading-rank": "^3.0.0", - "hast-util-to-string": "^3.0.0", - "unist-util-visit": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/renderkid": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", - "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", - "dev": true, - "dependencies": { - "css-select": "^4.1.3", - "dom-converter": "^0.2.0", - "htmlparser2": "^6.1.0", - "lodash": "^4.17.21", - "strip-ansi": "^6.0.1" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requireindex": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", - "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", - "dev": true, - "engines": { - "node": ">=0.10.5" - } - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-array-concat": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", - "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-array-concat/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safe-regex-test": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-regex": "^1.1.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dev": true, - "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" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dev": true, - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/snake-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", - "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", - "dependencies": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/space-separated-tokens": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", - "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "dev": true, - "dependencies": { - "internal-slot": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/storybook": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/storybook/-/storybook-8.2.2.tgz", - "integrity": "sha512-xDT9gyzAEFQNeK7P+Mj/8bNzN+fbm6/4D6ihdSzmczayjydpNjMs74HDHMY6S4Bfu6tRVyEK2ALPGnr6ZVofBA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.24.4", - "@babel/types": "^7.24.0", - "@storybook/codemod": "8.2.2", - "@storybook/core": "8.2.2", - "@types/semver": "^7.3.4", - "@yarnpkg/fslib": "2.10.3", - "@yarnpkg/libzip": "2.3.0", - "chalk": "^4.1.0", - "commander": "^6.2.1", - "cross-spawn": "^7.0.3", - "detect-indent": "^6.1.0", - "envinfo": "^7.7.3", - "execa": "^5.0.0", - "fd-package-json": "^1.2.0", - "find-up": "^5.0.0", - "fs-extra": "^11.1.0", - "giget": "^1.0.0", - "globby": "^14.0.1", - "jscodeshift": "^0.15.1", - "leven": "^3.1.0", - "ora": "^5.4.1", - "prettier": "^3.1.1", - "prompts": "^2.4.0", - "semver": "^7.3.7", - "strip-json-comments": "^3.0.1", - "tempy": "^3.1.0", - "tiny-invariant": "^1.3.1", - "ts-dedent": "^2.0.0" - }, - "bin": { - "getstorybook": "bin/index.cjs", - "sb": "bin/index.cjs", - "storybook": "bin/index.cjs" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/storybook" - } - }, - "node_modules/storybook-addon-react-router-v6": { - "version": "2.0.15", - "resolved": "https://registry.npmjs.org/storybook-addon-react-router-v6/-/storybook-addon-react-router-v6-2.0.15.tgz", - "integrity": "sha512-4vOYIQwehlQLyXaCT9K0Iu0po2Z+pANGsqkfm/BQuAEjE9MoN7vrsrQLHINhKbmQVtNMmuS/oBR3GGNbqQ1gew==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "compare-versions": "^6.0.0", - "react-inspector": "6.0.2" - }, - "peerDependencies": { - "@storybook/blocks": "^7.0.0", - "@storybook/channels": "^7.0.0", - "@storybook/components": "^7.0.0", - "@storybook/core-events": "^7.0.0", - "@storybook/manager-api": "^7.0.0", - "@storybook/preview-api": "^7.0.0", - "@storybook/theming": "^7.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-router-dom": "^6.4.0" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } - } - }, - "node_modules/storybook/node_modules/commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/storybook/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/storybook/node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/storybook/node_modules/globby": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", - "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", - "dev": true, - "dependencies": { - "@sindresorhus/merge-streams": "^2.1.0", - "fast-glob": "^3.3.2", - "ignore": "^5.2.4", - "path-type": "^5.0.0", - "slash": "^5.1.0", - "unicorn-magic": "^0.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/storybook/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/storybook/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/storybook/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/storybook/node_modules/path-type": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", - "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/storybook/node_modules/slash": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", - "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", - "dev": true, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string.prototype.includes": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.0.tgz", - "integrity": "sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "node_modules/string.prototype.matchall": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", - "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.7", - "regexp.prototype.flags": "^1.5.2", - "set-function-name": "^2.0.2", - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.repeat": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", - "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", - "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", - "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz", - "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==", - "dev": true, - "dependencies": { - "min-indent": "^1.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/style-loader": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz", - "integrity": "sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w==", - "dev": true, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/stylis": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", - "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" - }, - "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/svg-parser": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", - "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" - }, - "node_modules/svgo": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", - "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", - "dependencies": { - "@trysound/sax": "0.2.0", - "commander": "^7.2.0", - "css-select": "^5.1.0", - "css-tree": "^2.3.1", - "css-what": "^6.1.0", - "csso": "^5.0.5", - "picocolors": "^1.0.0" - }, - "bin": { - "svgo": "bin/svgo" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/svgo" - } - }, - "node_modules/svgo/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "engines": { - "node": ">= 10" - } - }, - "node_modules/svgo/node_modules/css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/svgo/node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/svgo/node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/svgo/node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/svgo/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/swc-loader": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/swc-loader/-/swc-loader-0.2.6.tgz", - "integrity": "sha512-9Zi9UP2YmDpgmQVbyOPJClY0dwf58JDyDMQ7uRc4krmc72twNI2fvlBWHLqVekBpPc7h5NJkGVT1zNDxFrqhvg==", - "dev": true, - "dependencies": { - "@swc/counter": "^0.1.3" - }, - "peerDependencies": { - "@swc/core": "^1.2.147", - "webpack": ">=2" - } - }, - "node_modules/synckit": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", - "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", - "dev": true, - "dependencies": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "dev": true, - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/telejson": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/telejson/-/telejson-7.2.0.tgz", - "integrity": "sha512-1QTEcJkJEhc8OnStBx/ILRu5J2p0GjvWsBx56bmZRqnrkdBMUe+nX92jxV+p3dB4CP6PZCdJMQJwCggkNBMzkQ==", - "dev": true, - "dependencies": { - "memoizerific": "^1.11.3" - } - }, - "node_modules/temp": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz", - "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==", - "dev": true, - "dependencies": { - "rimraf": "~2.6.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/temp-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-3.0.0.tgz", - "integrity": "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==", - "dev": true, - "engines": { - "node": ">=14.16" - } - }, - "node_modules/temp/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/temp/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/temp/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/temp/node_modules/rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/tempy": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/tempy/-/tempy-3.1.0.tgz", - "integrity": "sha512-7jDLIdD2Zp0bDe5r3D2qtkd1QOCacylBuL7oa4udvN6v2pqr4+LcCr67C8DR1zkpaZ8XosF5m1yQSabKAW6f2g==", - "dev": true, - "dependencies": { - "is-stream": "^3.0.0", - "temp-dir": "^3.0.0", - "type-fest": "^2.12.2", - "unique-string": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tempy/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/terser": { - "version": "5.31.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.2.tgz", - "integrity": "sha512-LGyRZVFm/QElZHy/CPr/O4eNZOZIzsrQ92y4v9UJe/pFJjypje2yI3C2FmPtvUEnhadlSbmG2nXtdcjHOjCfxw==", - "dev": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.10", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", - "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.20", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.26.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/tiny-invariant": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", - "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", - "dev": true - }, - "node_modules/tinyspy": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", - "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", - "dev": true, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", - "dev": true, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/ts-dedent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", - "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", - "dev": true, - "engines": { - "node": ">=6.10" - } - }, - "node_modules/ts-loader": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", - "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "enhanced-resolve": "^5.0.0", - "micromatch": "^4.0.0", - "semver": "^7.3.4", - "source-map": "^0.7.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "typescript": "*", - "webpack": "^5.0.0" - } - }, - "node_modules/ts-loader/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/tsc-alias": { - "version": "1.8.10", - "resolved": "https://registry.npmjs.org/tsc-alias/-/tsc-alias-1.8.10.tgz", - "integrity": "sha512-Ibv4KAWfFkFdKJxnWfVtdOmB0Zi1RJVxcbPGiCDsFpCQSsmpWyuzHG3rQyI5YkobWwxFPEyQfu1hdo4qLG2zPw==", - "dev": true, - "dependencies": { - "chokidar": "^3.5.3", - "commander": "^9.0.0", - "globby": "^11.0.4", - "mylas": "^2.1.9", - "normalize-path": "^3.0.0", - "plimit-lit": "^1.2.6" - }, - "bin": { - "tsc-alias": "dist/bin/index.js" - } - }, - "node_modules/tsc-alias/node_modules/commander": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", - "dev": true, - "engines": { - "node": "^12.20.0 || >=14" - } - }, - "node_modules/tsconfig-paths": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", - "dev": true, - "dependencies": { - "json5": "^2.2.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "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" - } - }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tween-functions": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tween-functions/-/tween-functions-1.2.0.tgz", - "integrity": "sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", - "dev": true, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", - "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typescript": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", - "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.16.0.tgz", - "integrity": "sha512-kaVRivQjOzuoCXU6+hLnjo3/baxyzWVO5GrnExkFzETRYJKVHYkrJglOu2OCm8Hi9RPDWX1PTNNTpU5KRV0+RA==", - "dev": true, - "dependencies": { - "@typescript-eslint/eslint-plugin": "7.16.0", - "@typescript-eslint/parser": "7.16.0", - "@typescript-eslint/utils": "7.16.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.0.tgz", - "integrity": "sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.16.0", - "@typescript-eslint/types": "7.16.0", - "@typescript-eslint/typescript-estree": "7.16.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - } - }, - "node_modules/ufo": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.3.tgz", - "integrity": "sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==", - "dev": true - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicorn-magic": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", - "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/unique-string": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", - "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", - "dev": true, - "dependencies": { - "crypto-random-string": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/unist-util-is": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", - "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", - "dev": true, - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", - "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", - "dev": true, - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit-parents": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", - "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", - "dev": true, - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/unplugin": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.11.0.tgz", - "integrity": "sha512-3r7VWZ/webh0SGgJScpWl2/MRCZK5d3ZYFcNaeci/GQ7Teop7zf0Nl2pUuz7G21BwPd9pcUPOC5KmJ2L3WgC5g==", - "dev": true, - "dependencies": { - "acorn": "^8.11.3", - "chokidar": "^3.6.0", - "webpack-sources": "^3.2.3", - "webpack-virtual-modules": "^0.6.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.3.tgz", - "integrity": "sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==", - "dev": true, - "dependencies": { - "punycode": "^1.4.1", - "qs": "^6.11.2" - } - }, - "node_modules/url/node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", - "dev": true - }, - "node_modules/url/node_modules/qs": { - "version": "6.12.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.3.tgz", - "integrity": "sha512-AWJm14H1vVaO/iNZ4/hO+HyaTehuy9nRqVdkTqlJt0HWvBiBIEXFmb4C0DGeYo3Xes9rrEW+TxHsaigCbN5ICQ==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/util": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", - "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "which-typed-array": "^1.1.2" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/utila": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", - "dev": true - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/walk-up-path": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-3.0.1.tgz", - "integrity": "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==", - "dev": true - }, - "node_modules/watchpack": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", - "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", - "dev": true, - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dev": true, - "dependencies": { - "defaults": "^1.0.3" - } - }, - "node_modules/webpack": { - "version": "5.93.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.93.0.tgz", - "integrity": "sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA==", - "dev": true, - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.5", - "@webassemblyjs/ast": "^1.12.1", - "@webassemblyjs/wasm-edit": "^1.12.1", - "@webassemblyjs/wasm-parser": "^1.12.1", - "acorn": "^8.7.1", - "acorn-import-attributes": "^1.9.5", - "browserslist": "^4.21.10", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.0", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.10", - "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-hot-middleware": { - "version": "2.26.1", - "resolved": "https://registry.npmjs.org/webpack-hot-middleware/-/webpack-hot-middleware-2.26.1.tgz", - "integrity": "sha512-khZGfAeJx6I8K9zKohEWWYN6KDlVw2DHownoe+6Vtwj1LP9WFgegXnVMSkZ/dBEBtXFwrkkydsaPFlB7f8wU2A==", - "dev": true, - "dependencies": { - "ansi-html-community": "0.0.8", - "html-entities": "^2.1.0", - "strip-ansi": "^6.0.0" - } - }, - "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack-virtual-modules": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", - "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", - "dev": true - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", - "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", - "dev": true, - "dependencies": { - "function.prototype.name": "^1.1.5", - "has-tostringtag": "^1.0.0", - "is-async-function": "^2.0.0", - "is-date-object": "^1.0.5", - "is-finalizationregistry": "^1.0.2", - "is-generator-function": "^1.0.10", - "is-regex": "^1.1.4", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/which-collection": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", - "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", - "dev": true, - "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/HDesign/package.json b/HDesign/package.json deleted file mode 100644 index b587d3be8..000000000 --- a/HDesign/package.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "name": "haengdong-design", - "version": "0.1.35", - "description": "", - "main": "./dist/index.js", - "module": "./dist/index.js", - "types": "./dist/index.d.ts", - "files": [ - "dist" - ], - "scripts": { - "start": "webpack serve ", - "build": "rm -rf dist && mkdir dist && tsc && cp -r ./src/assets ./dist && tsc-alias", - "storybook": "storybook dev -p 6006", - "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'", - "format": "prettier --write {src/**/*.{js,jsx,ts,tsx,json,css,scss,md}'", - "build-storybook": "storybook build" - }, - "keywords": [], - "author": "", - "license": "ISC", - "devDependencies": { - "@chromatic-com/storybook": "^1.6.1", - "@eslint/compat": "^1.1.0", - "@eslint/js": "^9.6.0", - "@storybook/addon-essentials": "^8.2.2", - "@storybook/addon-interactions": "^8.2.2", - "@storybook/addon-links": "^8.2.2", - "@storybook/addon-onboarding": "^8.2.2", - "@storybook/addon-webpack5-compiler-swc": "^1.0.4", - "@storybook/blocks": "^8.2.2", - "@storybook/react": "^8.2.2", - "@storybook/react-webpack5": "^8.2.3", - "@storybook/test": "^8.2.2", - "@types/react": "^18.3.3", - "@types/react-dom": "^18.3.0", - "@typescript-eslint/eslint-plugin": "^7.16.0", - "@typescript-eslint/parser": "^7.16.0", - "eslint": "^9.7.0", - "eslint-config-prettier": "^9.1.0", - "eslint-import-resolver-typescript": "^3.6.1", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jsx-a11y": "^6.9.0", - "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-react": "^7.34.4", - "eslint-plugin-react-hooks": "^4.6.2", - "eslint-plugin-storybook": "^0.8.0", - "file-loader": "^6.2.0", - "globals": "^15.8.0", - "prettier": "3.3.2", - "storybook": "^8.2.2", - "storybook-addon-react-router-v6": "^2.0.15", - "ts-loader": "^9.5.1", - "tsc-alias": "^1.8.10", - "typescript": "^5.5.3", - "typescript-eslint": "^7.16.0" - }, - "dependencies": { - "@emotion/react": "^11.11.4", - "@svgr/webpack": "^8.1.0", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "react-router-dom": "^6.24.1" - }, - "engines": { - "npm": ">=10.7.0", - "node": ">=20.15.1" - } -} diff --git a/HDesign/src/assets/arrow.svg b/HDesign/src/assets/arrow.svg deleted file mode 100644 index 4d8bac605..000000000 --- a/HDesign/src/assets/arrow.svg +++ /dev/null @@ -1,3 +0,0 @@ -<svg width="8" height="12" viewBox="0 0 8 12" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M1 1.5L6 6L1 10.5" stroke="black" stroke-opacity="0.4" stroke-width="1.5" stroke-linecap="round"/> -</svg> diff --git a/HDesign/src/assets/buljusa.svg b/HDesign/src/assets/buljusa.svg deleted file mode 100644 index e8008a2fb..000000000 --- a/HDesign/src/assets/buljusa.svg +++ /dev/null @@ -1,4 +0,0 @@ -<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M6.375 12.5C6.54076 12.5 6.69973 12.4407 6.81694 12.3352C6.93415 12.2298 7 12.0867 7 11.9375C7 11.7883 6.93415 11.6452 6.81694 11.5398C6.69973 11.4343 6.54076 11.375 6.375 11.375C6.20924 11.375 6.05027 11.4343 5.93306 11.5398C5.81585 11.6452 5.75 11.7883 5.75 11.9375C5.75 12.0867 5.81585 12.2298 5.93306 12.3352C6.05027 12.4407 6.20924 12.5 6.375 12.5ZM6.375 8.5625C6.54076 8.5625 6.69973 8.50324 6.81694 8.39775C6.93415 8.29226 7 8.14918 7 8C7 7.85082 6.93415 7.70774 6.81694 7.60225C6.69973 7.49676 6.54076 7.4375 6.375 7.4375C6.20924 7.4375 6.05027 7.49676 5.93306 7.60225C5.81585 7.70774 5.75 7.85082 5.75 8C5.75 8.14918 5.81585 8.29226 5.93306 8.39775C6.05027 8.50324 6.20924 8.5625 6.375 8.5625ZM6.375 4.625C6.54076 4.625 6.69973 4.56574 6.81694 4.46025C6.93415 4.35476 7 4.21168 7 4.0625C7 3.91332 6.93415 3.77024 6.81694 3.66475C6.69973 3.55926 6.54076 3.5 6.375 3.5C6.20924 3.5 6.05027 3.55926 5.93306 3.66475C5.81585 3.77024 5.75 3.91332 5.75 4.0625C5.75 4.21168 5.81585 4.35476 5.93306 4.46025C6.05027 4.56574 6.20924 4.625 6.375 4.625Z" fill="#B2B1B6" stroke="#B2B1B6"/> -<path d="M9.625 12.5C9.79076 12.5 9.94973 12.4407 10.0669 12.3352C10.1842 12.2298 10.25 12.0867 10.25 11.9375C10.25 11.7883 10.1842 11.6452 10.0669 11.5398C9.94973 11.4343 9.79076 11.375 9.625 11.375C9.45924 11.375 9.30027 11.4343 9.18306 11.5398C9.06585 11.6452 9 11.7883 9 11.9375C9 12.0867 9.06585 12.2298 9.18306 12.3352C9.30027 12.4407 9.45924 12.5 9.625 12.5ZM9.625 8.5625C9.79076 8.5625 9.94973 8.50324 10.0669 8.39775C10.1842 8.29226 10.25 8.14918 10.25 8C10.25 7.85082 10.1842 7.70774 10.0669 7.60225C9.94973 7.49676 9.79076 7.4375 9.625 7.4375C9.45924 7.4375 9.30027 7.49676 9.18306 7.60225C9.06585 7.70774 9 7.85082 9 8C9 8.14918 9.06585 8.29226 9.18306 8.39775C9.30027 8.50324 9.45924 8.5625 9.625 8.5625ZM9.625 4.625C9.79076 4.625 9.94973 4.56574 10.0669 4.46025C10.1842 4.35476 10.25 4.21168 10.25 4.0625C10.25 3.91332 10.1842 3.77024 10.0669 3.66475C9.94973 3.55926 9.79076 3.5 9.625 3.5C9.45924 3.5 9.30027 3.55926 9.18306 3.66475C9.06585 3.77024 9 3.91332 9 4.0625C9 4.21168 9.06585 4.35476 9.18306 4.46025C9.30027 4.56574 9.45924 4.625 9.625 4.625Z" fill="#B2B1B6" stroke="#B2B1B6"/> -</svg> diff --git a/HDesign/src/assets/index.ts b/HDesign/src/assets/index.ts deleted file mode 100644 index 3f92063cd..000000000 --- a/HDesign/src/assets/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export {default as InputDelete} from '@assets/inputDelete.svg'; -export {default as Plus} from '@assets/plus.svg'; -export {default as Buljusa} from '@assets/buljusa.svg'; -export {default as Arrow} from '@assets/arrow.svg'; diff --git a/HDesign/src/assets/inputDelete.svg b/HDesign/src/assets/inputDelete.svg deleted file mode 100644 index 06d850889..000000000 --- a/HDesign/src/assets/inputDelete.svg +++ /dev/null @@ -1,4 +0,0 @@ -<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> -<rect width="20" height="20" rx="10" fill="#B2B1B6"/> -<path d="M14 6L6 14M6 6L14 14" stroke="#E7E6EB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> -</svg> diff --git a/HDesign/src/assets/plus.svg b/HDesign/src/assets/plus.svg deleted file mode 100644 index 458dca8fd..000000000 --- a/HDesign/src/assets/plus.svg +++ /dev/null @@ -1,4 +0,0 @@ -<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"> -<rect x="0.5" width="32" height="32" rx="8" fill="#F4E8FF"/> -<path d="M24.5 17.1429H17.6429V24H15.3571V17.1429H8.5V14.8571H15.3571V8H17.6429V14.8571H24.5V17.1429Z" fill="#8425EC"/> -</svg> diff --git a/HDesign/src/assets/svg.d.ts b/HDesign/src/assets/svg.d.ts deleted file mode 100644 index 2db81e756..000000000 --- a/HDesign/src/assets/svg.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module '*.svg' { - import type React from 'react'; - - const SVG: React.FC<React.SVGProps<SVGSVGElement>>; - export default SVG; -} diff --git a/HDesign/src/components/BillItem/BillItem.stories.tsx b/HDesign/src/components/BillItem/BillItem.stories.tsx deleted file mode 100644 index efe1fbb83..000000000 --- a/HDesign/src/components/BillItem/BillItem.stories.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import type {Meta, StoryObj} from '@storybook/react'; - -import BillItem from '@components/BillItem/BillItem'; - -const meta = { - title: 'Components/BillItem', - component: BillItem, - tags: ['autodocs'], - parameters: { - // layout: 'centered', - }, - argTypes: { - name: { - description: '', - control: {type: 'text'}, - }, - price: { - description: '', - control: {type: 'number'}, - }, - }, - args: { - name: '뽕쟁이족발', - price: 198000, - }, -} satisfies Meta<typeof BillItem>; - -export default meta; - -type Story = StoryObj<typeof meta>; - -export const Playground: Story = {}; diff --git a/HDesign/src/components/BillItem/BillItem.style.ts b/HDesign/src/components/BillItem/BillItem.style.ts deleted file mode 100644 index 54531e095..000000000 --- a/HDesign/src/components/BillItem/BillItem.style.ts +++ /dev/null @@ -1,8 +0,0 @@ -import {css} from '@emotion/react'; - -import {Theme} from '@/theme/theme.type'; - -export const textStyle = (theme: Theme) => - css({ - color: theme.colors.black, - }); diff --git a/HDesign/src/components/BillItem/BillItem.tsx b/HDesign/src/components/BillItem/BillItem.tsx deleted file mode 100644 index f73c5d32d..000000000 --- a/HDesign/src/components/BillItem/BillItem.tsx +++ /dev/null @@ -1,34 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import React from 'react'; - -import Text from '@components/Text/Text'; - -import {useTheme} from '@theme/HDesignProvider'; - -import DragHandleItem from '../DragHandleItem/DragHandleItem'; -import Flex from '../Flex/Flex'; - -import {BillItemProps} from './BillItem.type'; -import {textStyle} from './BillItem.style'; - -export const BillItem: React.FC<BillItemProps> = ({ - name = '', - price = 0, - hasDragHandle = false, - ...htmlProps -}: BillItemProps) => { - const {theme} = useTheme(); - return ( - <DragHandleItem {...htmlProps} hasDragHandle={hasDragHandle} backgroundColor="lightGrayContainer"> - <Flex justifyContent="spaceBetween" width="100%"> - <Text css={textStyle(theme)} size="bodyBold"> - {name} - </Text> - <Text css={textStyle(theme)} size="body"> - {price.toLocaleString('ko-kr')}원 - </Text> - </Flex> - </DragHandleItem> - ); -}; -export default BillItem; diff --git a/HDesign/src/components/BillItem/BillItem.type.ts b/HDesign/src/components/BillItem/BillItem.type.ts deleted file mode 100644 index 4d6487ac9..000000000 --- a/HDesign/src/components/BillItem/BillItem.type.ts +++ /dev/null @@ -1,11 +0,0 @@ -export interface BillItemStyleProps {} - -export interface BillItemCustomProps { - name?: string; - price?: number; - hasDragHandle?: boolean; -} - -export type BillItemOptionProps = BillItemStyleProps & BillItemCustomProps; - -export type BillItemProps = React.ComponentProps<'div'> & BillItemOptionProps; diff --git a/HDesign/src/components/BottomSheet/BottomSheet.stories.tsx b/HDesign/src/components/BottomSheet/BottomSheet.stories.tsx deleted file mode 100644 index 48288fb6c..000000000 --- a/HDesign/src/components/BottomSheet/BottomSheet.stories.tsx +++ /dev/null @@ -1,49 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import type {Meta, StoryObj} from '@storybook/react'; - -import {useState} from 'react'; - -import Button from '@components/Button/Button'; -import BottomSheet from '@components/BottomSheet/BottomSheet'; - -const meta = { - title: 'Components/BottomSheet', - component: BottomSheet, - tags: ['autodocs'], - parameters: { - // layout: 'centered', - }, - argTypes: { - fixedButtonProps: { - description: '', - control: {type: 'object'}, - }, - }, - args: { - fixedButtonProps: { - variants: 'primary', - }, - }, -} satisfies Meta<typeof BottomSheet>; - -export default meta; - -type Story = StoryObj<typeof meta>; - -export const Playground: Story = { - args: { - fixedButtonProps: { - variants: 'primary', - children: '하단 고정 버튼', - }, - }, - render: ({...args}) => { - const [isOpened, setIsOpened] = useState(false); - return ( - <> - <Button variants="tertiary" children="show modal" onClick={() => setIsOpened(true)} /> - <BottomSheet {...args} isOpened={isOpened} onChangeClose={() => setIsOpened(false)} /> - </> - ); - }, -}; diff --git a/HDesign/src/components/BottomSheet/BottomSheet.style.ts b/HDesign/src/components/BottomSheet/BottomSheet.style.ts deleted file mode 100644 index 4968206f1..000000000 --- a/HDesign/src/components/BottomSheet/BottomSheet.style.ts +++ /dev/null @@ -1,40 +0,0 @@ -import {css} from '@emotion/react'; - -import {Theme} from '@theme/theme.type'; - -export const dimmedLayerStyle = (theme: Theme) => - css({ - // TODO: (@todari) zindex foundation - position: 'fixed', - zIndex: '30', - inset: '0', - width: '100vw', - height: '100vh', - backgroundColor: theme.colors.black, - opacity: '0.48', - }); - -export const bottomSheetContainerStyle = (theme: Theme) => - css({ - position: 'fixed', - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - gap: '1.5rem', - zIndex: '50', - inset: 'auto 0 0 0', - width: '100%', - height: '80%', - borderRadius: '1.5rem 1.5rem 0 0', - backgroundColor: theme.colors.white, - }); - -export const indicatorStyle = (theme: Theme) => - css({ - display: 'flex', - margin: '0.5rem 0', - width: '5rem', - height: '0.25rem', - borderRadius: '0.125rem', - backgroundColor: theme.colors.gray, - }); diff --git a/HDesign/src/components/BottomSheet/BottomSheet.tsx b/HDesign/src/components/BottomSheet/BottomSheet.tsx deleted file mode 100644 index d0f286cc8..000000000 --- a/HDesign/src/components/BottomSheet/BottomSheet.tsx +++ /dev/null @@ -1,39 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import {createPortal} from 'react-dom'; - -import {BottomSheetProps} from '@components/BottomSheet/BottomSheet.type'; -import FixedButton from '@components/FixedButton/FixedButton'; - -import {useTheme} from '@theme/HDesignProvider'; - -import {useBottomSheet} from './useBottomSheet'; -import {bottomSheetContainerStyle, dimmedLayerStyle, indicatorStyle} from './BottomSheet.style'; - -const BottomSheet: React.FC<BottomSheetProps> = ({ - isOpened = false, - children, - fixedButtonProps, - ...props -}: BottomSheetProps) => { - const {theme} = useTheme(); - const {opened, handleClose} = useBottomSheet({isOpened, ...props}); - - // TODO: (@todari) : children 길이 길 때 overflow button에 안가리는 영역 처리 - return createPortal( - <> - {opened && ( - <> - <div css={dimmedLayerStyle(theme)} onClick={handleClose} /> - <div css={bottomSheetContainerStyle(theme)}> - <div css={indicatorStyle(theme)} /> - {children} - {fixedButtonProps && <FixedButton {...fixedButtonProps} />} - </div> - </> - )} - </>, - document.body, - ); -}; - -export default BottomSheet; diff --git a/HDesign/src/components/BottomSheet/BottomSheet.type.ts b/HDesign/src/components/BottomSheet/BottomSheet.type.ts deleted file mode 100644 index 312fe3c29..000000000 --- a/HDesign/src/components/BottomSheet/BottomSheet.type.ts +++ /dev/null @@ -1,22 +0,0 @@ -import {ComponentPropsWithoutRef} from 'react'; - -import {ButtonVariants} from '@components/Button/Button.type'; - -import {Theme} from '@theme/theme.type'; - -import {FixedButtonProps} from '../FixedButton/FixedButton.type'; - -export interface BottomSheetStyleProps { - theme?: Theme; -} - -export interface BottomSheetCustomProps { - isOpened?: boolean; - onChangeOpen?: () => void; - onChangeClose?: () => void; - fixedButtonProps?: FixedButtonProps; -} - -export type BottomSheetOptionProps = BottomSheetStyleProps & BottomSheetCustomProps; - -export type BottomSheetProps = ComponentPropsWithoutRef<'div'> & BottomSheetOptionProps; diff --git a/HDesign/src/components/BottomSheet/useBottomSheet.ts b/HDesign/src/components/BottomSheet/useBottomSheet.ts deleted file mode 100644 index ca2274e19..000000000 --- a/HDesign/src/components/BottomSheet/useBottomSheet.ts +++ /dev/null @@ -1,52 +0,0 @@ -import {useCallback, useEffect, useState} from 'react'; - -interface UseBottomSheetProps { - isOpened: boolean; - onChangeClose?: () => void; - onChangeOpen?: () => void; -} - -export const useBottomSheet = ({isOpened, onChangeClose, onChangeOpen}: UseBottomSheetProps) => { - const [opened, setOpened] = useState(false); - - useEffect(() => { - setOpened(isOpened); - if (!isOpened) { - handleClose(); - } else { - handleOpen(); - } - }, [isOpened]); - - const handleClose = useCallback(() => { - setOpened(false); - if (onChangeClose) { - onChangeClose(); - } - }, []); - - const handleOpen = useCallback(() => { - setOpened(true); - if (onChangeOpen) { - onChangeOpen(); - } - }, []); - - useEffect(() => { - document.body.style.overflow = 'hidden'; - document.body.addEventListener('keydown', handleKeyDownEsc); - - return () => { - document.body.style.overflow = 'scroll'; - document.body.removeEventListener('keydown', handleKeyDownEsc); - }; - }, [isOpened]); - - const handleKeyDownEsc = (e: KeyboardEvent) => { - if (e.key === 'Escape' && isOpened) { - handleClose(); - } - }; - - return {opened, handleClose}; -}; diff --git a/HDesign/src/components/Button/Button.stories.tsx b/HDesign/src/components/Button/Button.stories.tsx deleted file mode 100644 index 2e8b00bb3..000000000 --- a/HDesign/src/components/Button/Button.stories.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import type {Meta, StoryObj} from '@storybook/react'; - -import Button from './Button'; - -const meta = { - title: 'Components/Button', - component: Button, - tags: ['autodocs'], - parameters: { - layout: 'centered', - }, - argTypes: { - variants: { - description: '', - control: {type: 'select'}, - options: ['', 'primary', 'secondary', 'tertiary'], - }, - size: { - description: '', - control: {type: 'select'}, - options: ['', 'small', 'medium', 'large'], - }, - disabled: { - description: '', - control: {type: 'boolean'}, - }, - }, - args: { - variants: 'primary', - size: 'medium', - disabled: false, - children: 'button', - }, -} satisfies Meta<typeof Button>; - -export default meta; - -type Story = StoryObj<typeof meta>; - -export const Playground: Story = {}; diff --git a/HDesign/src/components/Button/Button.style.ts b/HDesign/src/components/Button/Button.style.ts deleted file mode 100644 index b0a3720ac..000000000 --- a/HDesign/src/components/Button/Button.style.ts +++ /dev/null @@ -1,72 +0,0 @@ -import {css} from '@emotion/react'; - -import {Theme} from '../../theme/theme.type'; - -import {ButtonStyleProps, ButtonSize, ButtonVariants} from './Button.type'; - -export const buttonStyle = (props: Required<ButtonStyleProps>) => { - return [ - getButtonDefaultStyle(props.theme), - getButtonSizeStyle(props.size), - getButtonVariantsStyle(props.variants, props.theme), - ]; -}; - -const getButtonDefaultStyle = (theme: Theme) => - css({ - display: 'flex', - justifyContent: 'center', - lineHeight: '1', - - '&:disabled': { - backgroundColor: theme.colors.tertiary, - color: theme.colors.onPrimary, - }, - }); - -const getButtonSizeStyle = (size: ButtonSize) => { - const style = { - small: css({ - padding: '0.5rem 0.75rem', - borderRadius: '0.75rem', - fontFamily: 'Pretendard', - fontSize: '0.75rem', - fontWeight: '400', - }), - medium: css({ - padding: '0.75rem 1rem', - borderRadius: '1rem', - fontFamily: 'Pretendard', - fontSize: '1rem', - fontWeight: '700', - }), - large: css({ - padding: '1rem 1.5rem', - borderRadius: '1.25rem', - fontFamily: 'Pretendard', - fontSize: '1.25rem', - fontWeight: '700', - }), - }; - - return style[size]; -}; - -const getButtonVariantsStyle = (variants: ButtonVariants, theme: Theme) => { - const style = { - primary: css({ - backgroundColor: theme.colors.primary, - color: theme.colors.onPrimary, - }), - secondary: css({ - backgroundColor: theme.colors.secondary, - color: theme.colors.onSecondary, - }), - tertiary: css({ - backgroundColor: theme.colors.tertiary, - color: theme.colors.onTertiary, - }), - }; - - return style[variants]; -}; diff --git a/HDesign/src/components/Button/Button.tsx b/HDesign/src/components/Button/Button.tsx deleted file mode 100644 index ca78350a1..000000000 --- a/HDesign/src/components/Button/Button.tsx +++ /dev/null @@ -1,18 +0,0 @@ -/** @jsxImportSource @emotion/react */ - -import React, {forwardRef} from 'react'; - -import {buttonStyle} from '@components/Button/Button.style'; -import {ButtonProps} from '@components/Button/Button.type'; - -import {useTheme} from '@theme/HDesignProvider'; - -export const Button: React.FC<ButtonProps> = forwardRef<HTMLButtonElement, ButtonProps>(function Button( - {variants = 'primary', size = 'medium', ...htmlProps}: ButtonProps, - ref, -) { - const {theme} = useTheme(); - return <button css={buttonStyle({variants, size, theme})} ref={ref} {...htmlProps} />; -}); - -export default Button; diff --git a/HDesign/src/components/Button/Button.type.ts b/HDesign/src/components/Button/Button.type.ts deleted file mode 100644 index 7c200574f..000000000 --- a/HDesign/src/components/Button/Button.type.ts +++ /dev/null @@ -1,16 +0,0 @@ -import {Theme} from '@theme/theme.type'; - -export type ButtonSize = 'small' | 'medium' | 'large'; -export type ButtonVariants = 'primary' | 'secondary' | 'tertiary'; - -export interface ButtonStyleProps { - variants?: ButtonVariants; - size?: ButtonSize; - theme?: Theme; -} - -export interface ButtonCustomProps {} - -export type ButtonOptionProps = ButtonStyleProps & ButtonCustomProps; - -export type ButtonProps = React.ComponentProps<'button'> & ButtonOptionProps; diff --git a/HDesign/src/components/DragHandleItem/DragHandleItem.stories.tsx b/HDesign/src/components/DragHandleItem/DragHandleItem.stories.tsx deleted file mode 100644 index 773c181a2..000000000 --- a/HDesign/src/components/DragHandleItem/DragHandleItem.stories.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import type {Meta, StoryObj} from '@storybook/react'; - -import DragHandleItem from '@components/DragHandleItem/DragHandleItem'; - -const meta = { - title: 'Components/DragHandleItem', - component: DragHandleItem, - tags: ['autodocs'], - parameters: {}, - argTypes: { - backgroundColor: { - description: '', - control: {type: 'select'}, - options: ['white', 'gray', 'darkGray', 'black', 'primary', 'onPrimary', 'secondary', 'onSecondary'], - }, - hasDragHandle: { - description: '드래그할 수 있는 핸들러(불주사 자국)를 켜고 끌 수 있습니다.', - control: {type: 'boolean'}, - }, - }, - args: { - backgroundColor: 'white', - children: '이건 끌 수 있는 아이템을 위한 것', - }, -} satisfies Meta<typeof DragHandleItem>; - -export default meta; - -type Story = StoryObj<typeof meta>; - -export const Playground: Story = {}; diff --git a/HDesign/src/components/DragHandleItem/DragHandleItem.style.ts b/HDesign/src/components/DragHandleItem/DragHandleItem.style.ts deleted file mode 100644 index 972050619..000000000 --- a/HDesign/src/components/DragHandleItem/DragHandleItem.style.ts +++ /dev/null @@ -1,19 +0,0 @@ -import {css} from '@emotion/react'; - -import {Theme} from '@/theme/theme.type'; -import {ColorKeys} from '@/token/colors'; - -export const dragHandleItemStyle = (theme: Theme, hasDragHandle: boolean, backgroundColor: ColorKeys) => - css({ - display: 'flex', - justifyContent: 'space-between', - padding: hasDragHandle ? '0.5rem 0.5rem 0.5rem 0.25rem' : '0.5rem', - borderRadius: '0.5rem', - backgroundColor: theme.colors[backgroundColor], - }); - -export const prefixStyle = css({ - display: 'flex', - gap: '0.25rem', - width: '100%', -}); diff --git a/HDesign/src/components/DragHandleItem/DragHandleItem.tsx b/HDesign/src/components/DragHandleItem/DragHandleItem.tsx deleted file mode 100644 index 9c92a6c8f..000000000 --- a/HDesign/src/components/DragHandleItem/DragHandleItem.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import React from 'react'; - -import {StrictPropsWithChildren} from '@/types/strictPropsWithChildren'; -import {COLORS, ColorKeys} from '@/token/colors'; - -import {useTheme} from '@theme/HDesignProvider'; - -import IconButton from '../IconButton/IconButton'; - -import {dragHandleItemStyle, prefixStyle} from './DragHandleItem.style'; - -interface DragHandleItemCustomProps { - hasDragHandle?: boolean; - backgroundColor?: ColorKeys; -} - -export type DragHandleItemProps = React.ComponentProps<'div'> & DragHandleItemCustomProps; - -export function DragHandleItem({ - hasDragHandle = false, - backgroundColor = 'white', - children, - ...htmlProps -}: StrictPropsWithChildren<DragHandleItemProps>) { - const {theme} = useTheme(); - - // TODO: (@toari) : 사람 수 많을 때 UX writing 처리 - return ( - <div css={dragHandleItemStyle(theme, hasDragHandle, backgroundColor)} {...htmlProps}> - <div css={prefixStyle}> - {hasDragHandle && <IconButton iconType="buljusa" />} - {children} - </div> - </div> - ); -} -export default DragHandleItem; diff --git a/HDesign/src/components/ExpenseList/ExpenseList.stories.tsx b/HDesign/src/components/ExpenseList/ExpenseList.stories.tsx deleted file mode 100644 index ccf8e28de..000000000 --- a/HDesign/src/components/ExpenseList/ExpenseList.stories.tsx +++ /dev/null @@ -1,29 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import type {Meta, StoryObj} from '@storybook/react'; - -import ExpenseList from '@components/ExpenseList/ExpenseList'; - -const meta = { - title: 'Components/ExpenseList', - component: ExpenseList, - tags: ['autodocs'], - argTypes: { - expenseList: { - description: '', - }, - }, - args: { - expenseList: [ - {name: '소하', price: 2000}, - {name: '토다리', price: 2000}, - {name: '웨디', price: 1080}, - {name: '쿠키', price: 3020}, - ], - }, -} satisfies Meta<typeof ExpenseList>; - -export default meta; - -type Story = StoryObj<typeof meta>; - -export const Playground: Story = {}; diff --git a/HDesign/src/components/ExpenseList/ExpenseList.style.ts b/HDesign/src/components/ExpenseList/ExpenseList.style.ts deleted file mode 100644 index 58c8ba7f5..000000000 --- a/HDesign/src/components/ExpenseList/ExpenseList.style.ts +++ /dev/null @@ -1,34 +0,0 @@ -import {css} from '@emotion/react'; - -import {Theme} from '@/theme/theme.type'; - -export const expenseItemStyle = () => - css({ - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - width: '100%', - height: '2.5rem', - padding: '0.5rem 1rem', - }); - -export const expenseItemLeftStyle = () => - css({ - display: 'flex', - alignItems: 'center', - gap: '1rem', - }); - -export const TextStyle = (theme: Theme) => - css({ - color: theme.colors.onTertiary, - }); - -export const expenseListStyle = (theme: Theme) => - css({ - width: '100%', - backgroundColor: theme.colors.white, - padding: '0.5rem 0', - borderRadius: '1rem', - height: '100%', - }); diff --git a/HDesign/src/components/ExpenseList/ExpenseList.tsx b/HDesign/src/components/ExpenseList/ExpenseList.tsx deleted file mode 100644 index 2990458bb..000000000 --- a/HDesign/src/components/ExpenseList/ExpenseList.tsx +++ /dev/null @@ -1,45 +0,0 @@ -/** @jsxImportSource @emotion/react */ - -import Text from '@components/Text/Text'; - - -import {Arrow} from '@assets/index'; - -import {useTheme} from '@theme/HDesignProvider'; - -import {useTheme} from '@theme/HDesignProvider'; - -import {ExpenseItemProps, ExpenseListProps} from './ExpenseList.type'; -import {expenseItemStyle, expenseListStyle, expenseItemLeftStyle, TextStyle} from './ExpenseList.style'; - -// TODO: (@soha) 따로 파일 분리할까 고민중.. 여기서만 사용할 것 같긴 한데.. 흠 -function ExpenseItem({name, price, ...buttonProps}: ExpenseItemProps) { - const {theme} = useTheme(); - return ( - <button css={expenseItemStyle} {...buttonProps}> - <Text size="bodyBold" css={TextStyle(theme)}> - {name} - </Text> - <div css={expenseItemLeftStyle}> - <Text css={TextStyle(theme)}>{price.toLocaleString('ko-kr')}원</Text> - <Arrow /> - </div> - </button> - ); -} -} - -function ExpenseList({expenseList = []}: ExpenseListProps) { -function ExpenseList({expenseList = []}: ExpenseListProps) { - const {theme} = useTheme(); - return ( - <div css={expenseListStyle(theme)}> - {expenseList.map(({name, price}, index: number) => ( - <ExpenseItem key={name + index} name={name} price={price} /> - ))} - </div> - ); -} -} - -export default ExpenseList; diff --git a/HDesign/src/components/ExpenseList/ExpenseList.type.ts b/HDesign/src/components/ExpenseList/ExpenseList.type.ts deleted file mode 100644 index 939cd2f68..000000000 --- a/HDesign/src/components/ExpenseList/ExpenseList.type.ts +++ /dev/null @@ -1,10 +0,0 @@ -export interface ExpenseItemCustomProps { - name: string; - price: number; -} - -export type ExpenseItemProps = React.ComponentProps<'button'> & ExpenseItemCustomProps; - -export type ExpenseListProps = { - expenseList: ExpenseItemProps[]; -}; diff --git a/HDesign/src/components/FixedButton/FixedButton.stories.tsx b/HDesign/src/components/FixedButton/FixedButton.stories.tsx deleted file mode 100644 index a07260d2c..000000000 --- a/HDesign/src/components/FixedButton/FixedButton.stories.tsx +++ /dev/null @@ -1,40 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import type {Meta, StoryObj} from '@storybook/react'; - -import FixedButton from '@components/FixedButton/FixedButton'; - -const meta = { - title: 'Components/FixedButton', - component: FixedButton, - tags: ['autodocs'], - parameters: {}, - argTypes: { - variants: { - description: '', - control: {type: 'select'}, - options: ['', 'primary', 'secondary', 'tertiary'], - }, - disabled: { - description: '', - control: {type: 'boolean'}, - }, - }, - args: { - variants: 'primary', - disabled: false, - children: 'button', - }, - decorators: [ - Story => ( - <div style={{height: '420px'}}> - <Story /> - </div> - ), - ], -} satisfies Meta<typeof FixedButton>; - -export default meta; - -type Story = StoryObj<typeof meta>; - -export const Playground: Story = {}; diff --git a/HDesign/src/components/FixedButton/FixedButton.style.ts b/HDesign/src/components/FixedButton/FixedButton.style.ts deleted file mode 100644 index 19e011893..000000000 --- a/HDesign/src/components/FixedButton/FixedButton.style.ts +++ /dev/null @@ -1,60 +0,0 @@ -import {css} from '@emotion/react'; - -import {ButtonVariants} from '@components/Button/Button.type'; -import {FixedButtonStyleProps} from '@components/FixedButton/FixedButton.type'; - -import {Theme} from '@theme/theme.type'; - -export const fixedButtonContainerStyle = (theme: Theme) => - css({ - display: 'flex', - position: 'fixed', - maxWidth: '768px', - inset: 'auto 0 0', - margin: '0 auto', - backgroundColor: theme.colors.white, - boxSizing: 'border-box', - }); - -export const fixedButtonStyle = (props: Required<FixedButtonStyleProps>) => { - return [getFixedButtonDefaultStyle(props.theme), getFixedButtonVariantsStyle(props.variants, props.theme)]; -}; - -const getFixedButtonDefaultStyle = (theme: Theme) => - css({ - display: 'flex', - justifyContent: 'center', - padding: '1rem 1.5rem', - borderRadius: '1.25rem', - margin: '1.5rem 1rem 3rem 1rem', - width: '100%', - - fontFamily: 'Pretendard', - fontSize: '1.25rem', - fontWeight: '700', - lineHeight: '1', - - '&:disabled': { - backgroundColor: theme.colors.tertiary, - color: theme.colors.onPrimary, - }, - }); - -const getFixedButtonVariantsStyle = (variants: ButtonVariants, theme: Theme) => { - const style = { - primary: css({ - backgroundColor: theme.colors.primary, - color: theme.colors.onPrimary, - }), - secondary: css({ - backgroundColor: theme.colors.secondary, - color: theme.colors.onSecondary, - }), - tertiary: css({ - backgroundColor: theme.colors.tertiary, - color: theme.colors.onTertiary, - }), - }; - - return style[variants]; -}; diff --git a/HDesign/src/components/FixedButton/FixedButton.tsx b/HDesign/src/components/FixedButton/FixedButton.tsx deleted file mode 100644 index e98db5918..000000000 --- a/HDesign/src/components/FixedButton/FixedButton.tsx +++ /dev/null @@ -1,21 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import {forwardRef} from 'react'; - -import {fixedButtonContainerStyle, fixedButtonStyle} from '@components/FixedButton/FixedButton.style'; -import {FixedButtonProps} from '@components/FixedButton/FixedButton.type'; - -import {useTheme} from '@theme/HDesignProvider'; - -export const FixedButton: React.FC<FixedButtonProps> = forwardRef<HTMLButtonElement, FixedButtonProps>(function Button( - {variants = 'primary', ...htmlProps}: FixedButtonProps, - ref, -) { - const {theme} = useTheme(); - return ( - <div css={fixedButtonContainerStyle(theme)}> - <button css={fixedButtonStyle({variants, theme})} ref={ref} {...htmlProps} /> - </div> - ); -}); - -export default FixedButton; diff --git a/HDesign/src/components/FixedButton/FixedButton.type.ts b/HDesign/src/components/FixedButton/FixedButton.type.ts deleted file mode 100644 index 84f38ca35..000000000 --- a/HDesign/src/components/FixedButton/FixedButton.type.ts +++ /dev/null @@ -1,14 +0,0 @@ -import {ButtonVariants} from '@components/Button/Button.type'; - -import {Theme} from '@theme/theme.type'; - -export interface FixedButtonStyleProps { - variants?: ButtonVariants; - theme?: Theme; -} - -export interface ButtonCustomProps {} - -export type FixedButtonOptionProps = FixedButtonStyleProps; - -export type FixedButtonProps = React.ComponentProps<'button'> & FixedButtonOptionProps; diff --git a/HDesign/src/components/Flex/Flex.style.ts b/HDesign/src/components/Flex/Flex.style.ts deleted file mode 100644 index c86f1b64d..000000000 --- a/HDesign/src/components/Flex/Flex.style.ts +++ /dev/null @@ -1,45 +0,0 @@ -import {css} from '@emotion/react'; - -import {changeCamelCaseToKebabCase} from '@/utils/ return str.replace(/([a-z])([A-Z])/changeCamelCaseToKebabCase'; - -import {FlexDirectionStrictType, FlexProps} from './Flex.type'; - -export const flexStyle = ({ - justifyContent = 'flexStart', - alignItems = 'stretch', - flexDirection = 'row', - gap = '0', - padding = '0', - paddingInline = '0', - margin = '0', - width = 'auto', - height = 'auto', - backgroundColor, - theme, - ...rest -}: FlexProps) => - css({ - display: 'flex', - justifyContent: changeCamelCaseToKebabCase(justifyContent), - alignItems: changeCamelCaseToKebabCase(alignItems), - // TODO: (@weadie) as를 사용하지 않으면 방법이 없음. css의 flexDirection속성은 string을 받지 않고 명확한 속성명(ex row-reverse)를 받고 싶어함. 다만 as를 사용해도 된다고 생각한 근거는 케밥함수가 FlexDirectionType에 명시된 모든 타입을 정확하게 변환하며, 받는 문자열이 FlexDirectionType에 제한되기 때문. - flexDirection: changeCamelCaseToKebabCase(flexDirection) as FlexDirectionStrictType, - gap, - padding, - paddingInline, - margin, - width, - height, - ...rest, - - backgroundColor: (() => { - switch (backgroundColor) { - case 'white': - return theme?.colors.white; - case 'gray': - return theme?.colors.grayContainer; - default: - return 'none'; - } - })(), - }); diff --git a/HDesign/src/components/Flex/Flex.tsx b/HDesign/src/components/Flex/Flex.tsx deleted file mode 100644 index 57a5e7332..000000000 --- a/HDesign/src/components/Flex/Flex.tsx +++ /dev/null @@ -1,16 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import {css} from '@emotion/react'; - -import {StrictPropsWithChildren} from '@/types/strictPropsWithChildren'; -import {useTheme} from '@/theme/HDesignProvider'; - -import {FlexProps} from './Flex.type'; -import {flexStyle} from './Flex.style'; - -// TODO: (@weadie) 지정된 프롭 말고 다른 프롭도 가져올 수 있게 하자. -function Flex({children, ...props}: StrictPropsWithChildren<FlexProps>) { - const {theme} = useTheme(); - return <div css={flexStyle({theme, ...props})}>{children}</div>; -} - -export default Flex; diff --git a/HDesign/src/components/Flex/Flex.type.ts b/HDesign/src/components/Flex/Flex.type.ts deleted file mode 100644 index 75467e97e..000000000 --- a/HDesign/src/components/Flex/Flex.type.ts +++ /dev/null @@ -1,19 +0,0 @@ -import {Theme} from '@/theme/theme.type'; - -export type FlexDirectionType = 'row' | 'column' | 'rowReverse' | 'columnReverse'; -export type FlexDirectionStrictType = 'row' | 'column' | 'row-reverse' | 'column-reverse'; -export type FlexBackgroundColor = 'gray' | 'white'; - -export interface FlexProps { - justifyContent?: 'flexStart' | 'center' | 'flexEnd' | 'spaceBetween' | 'spaceAround' | 'spaceEvenly'; - alignItems?: 'flexStart' | 'center' | 'flexEnd' | 'stretch' | 'baseline'; - flexDirection?: FlexDirectionType; - gap?: string; - padding?: string; - paddingInline?: string; - margin?: string; - width?: string; - height?: string; - backgroundColor?: FlexBackgroundColor; - theme?: Theme; -} diff --git a/HDesign/src/components/IconButton/IconButton.stories.tsx b/HDesign/src/components/IconButton/IconButton.stories.tsx deleted file mode 100644 index 23b9f7bc5..000000000 --- a/HDesign/src/components/IconButton/IconButton.stories.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import type {Meta, StoryObj} from '@storybook/react'; - -import IconButton from '@components/IconButton/IconButton'; - -const meta = { - title: 'Components/IconButton', - component: IconButton, - tags: ['autodocs'], - parameters: { - layout: 'centered', - }, - argTypes: { - iconType: { - description: '', - control: {type: 'select'}, - options: ['plus', 'inputDelete', 'buljusa'], - }, - }, - args: { - iconType: 'plus', - }, -} satisfies Meta<typeof IconButton>; - -export default meta; - -type Story = StoryObj<typeof meta>; - -export const Playground: Story = {}; diff --git a/HDesign/src/components/IconButton/IconButton.tsx b/HDesign/src/components/IconButton/IconButton.tsx deleted file mode 100644 index 66d4c34b8..000000000 --- a/HDesign/src/components/IconButton/IconButton.tsx +++ /dev/null @@ -1,24 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import {forwardRef} from 'react'; - -import {IconButtonProps} from '@components/IconButton/IconButton.type'; -import {InputDelete, Plus, Buljusa} from '@/assets'; - -const ICON = { - inputDelete: <InputDelete />, - plus: <Plus />, - buljusa: <Buljusa />, -}; - -export const IconButton: React.FC<IconButtonProps> = forwardRef<HTMLButtonElement, IconButtonProps>(function Button( - {iconType, ...htmlProps}: IconButtonProps, - ref, -) { - return ( - <button ref={ref} {...htmlProps}> - {ICON[iconType]} - </button> - ); -}); - -export default IconButton; diff --git a/HDesign/src/components/IconButton/IconButton.type.ts b/HDesign/src/components/IconButton/IconButton.type.ts deleted file mode 100644 index 10415621c..000000000 --- a/HDesign/src/components/IconButton/IconButton.type.ts +++ /dev/null @@ -1,11 +0,0 @@ -type IconButtonType = 'inputDelete' | 'plus' | 'buljusa'; - -export interface IconButtonStyleProps {} - -export interface IconButtonCustomProps { - iconType: IconButtonType; -} - -export type IconButtonOptionProps = IconButtonStyleProps & IconButtonCustomProps; - -export type IconButtonProps = React.ComponentProps<'button'> & IconButtonOptionProps; diff --git a/HDesign/src/components/InOutItem/InOutItem.stories.tsx b/HDesign/src/components/InOutItem/InOutItem.stories.tsx deleted file mode 100644 index 1805fe0db..000000000 --- a/HDesign/src/components/InOutItem/InOutItem.stories.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import type {Meta, StoryObj} from '@storybook/react'; - -import InOutItem from '@components/InOutItem/InOutItem'; - -const meta = { - title: 'Components/InOutItem', - component: InOutItem, - tags: ['autodocs'], - parameters: { - // layout: 'centered', - }, - argTypes: { - names: { - description: '', - control: {type: 'object'}, - }, - inOutType: { - description: '', - control: {type: 'select', options: ['IN', 'OUT']}, - }, - }, - args: { - names: ['감자', '토다리'], - inOutType: 'OUT', - }, -} satisfies Meta<typeof InOutItem>; - -export default meta; - -type Story = StoryObj<typeof meta>; - -export const Playground: Story = {}; diff --git a/HDesign/src/components/InOutItem/InOutItem.style.ts b/HDesign/src/components/InOutItem/InOutItem.style.ts deleted file mode 100644 index b3f8eee46..000000000 --- a/HDesign/src/components/InOutItem/InOutItem.style.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {css} from '@emotion/react'; - -import {Theme} from '@/theme/theme.type'; - -export const inOutItemStyle = (theme: Theme) => - css({ - display: 'flex', - justifyContent: 'space-between', - padding: '0.5rem 0.5rem 0.5rem 0.25rem', - borderRadius: '0.5rem', - backgroundColor: theme.colors.white, - }); - -export const prefixStyle = css({ - display: 'flex', - gap: '0.25rem', -}); - -export const textStyle = (theme: Theme, hasDragHandle: boolean) => - css({ - paddingLeft: hasDragHandle ? '0' : '0.5rem', - - color: theme.colors.black, - }); diff --git a/HDesign/src/components/InOutItem/InOutItem.tsx b/HDesign/src/components/InOutItem/InOutItem.tsx deleted file mode 100644 index 9393c5e20..000000000 --- a/HDesign/src/components/InOutItem/InOutItem.tsx +++ /dev/null @@ -1,37 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import React from 'react'; - -import Text from '@components/Text/Text'; - -import Text from '@components/Text/Text'; - -import {useTheme} from '@theme/HDesignProvider'; - -import DragHandleItem from '../DragHandleItem/DragHandleItem'; - -import {InOutItemProps, InOutType} from './InOutItem.type'; -import {textStyle} from './InOutItem.style'; - -const IN_OUT_TEXT: Record<InOutType, string> = { - IN: '들어옴', - OUT: '나감', -}; - -export const InOutItem: React.FC<InOutItemProps> = ({ - names = [], - inOutType = 'OUT', - hasDragHandle = false, - ...htmlProps -}: InOutItemProps) => { - const {theme} = useTheme(); - - // TODO: (@toari) : 사람 수 많을 때 UX writing 처리 - return ( - <DragHandleItem {...htmlProps} hasDragHandle={hasDragHandle}> - <Text css={textStyle(theme, hasDragHandle)} size="bodyBold"> - {names.join(', ')} {IN_OUT_TEXT[inOutType]} - </Text> - </DragHandleItem> - ); -}; -export default InOutItem; diff --git a/HDesign/src/components/InOutItem/InOutItem.type.ts b/HDesign/src/components/InOutItem/InOutItem.type.ts deleted file mode 100644 index 2872e5d55..000000000 --- a/HDesign/src/components/InOutItem/InOutItem.type.ts +++ /dev/null @@ -1,13 +0,0 @@ -export type InOutType = 'IN' | 'OUT'; - -export interface InOutItemStyleProps {} - -export interface InOutItemCustomProps { - names?: string[]; - inOutType?: InOutType; - hasDragHandle?: boolean; -} - -export type InOutItemOptionProps = InOutItemStyleProps & InOutItemCustomProps; - -export type InOutItemProps = React.ComponentProps<'div'> & InOutItemOptionProps; diff --git a/HDesign/src/components/Input/Input.stories.tsx b/HDesign/src/components/Input/Input.stories.tsx deleted file mode 100644 index 0f5187cb3..000000000 --- a/HDesign/src/components/Input/Input.stories.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import type {Meta, StoryObj} from '@storybook/react'; - -import Input from '@components/Input/Input'; - -const meta = { - title: 'Components/Input', - component: Input, - tags: ['autodocs'], - parameters: { - // layout: 'centered', - }, - argTypes: { - value: { - description: '', - control: {type: 'text'}, - }, - inputType: { - // TODO: (@cookie) 스토리북 라디오버튼 보이도록 설정해야 함 - control: {type: 'radio'}, - }, - }, - args: { - disabled: false, - placeholder: 'placeholder', - }, -} satisfies Meta<typeof Input>; - -export default meta; - -type Story = StoryObj<typeof meta>; - -export const Playground: Story = {}; diff --git a/HDesign/src/components/Input/Input.style.ts b/HDesign/src/components/Input/Input.style.ts deleted file mode 100644 index 50980be64..000000000 --- a/HDesign/src/components/Input/Input.style.ts +++ /dev/null @@ -1,42 +0,0 @@ -import {css} from '@emotion/react'; - -import {Theme} from '@theme/theme.type'; - -import {InputType} from './Input.type'; - -const inputBoxBackgroundColorByInputType = (theme: Theme, inputType: InputType = 'input') => { - switch (inputType) { - case 'input': - return theme.colors.lightGrayContainer; - - case 'search': - return theme.colors.white; - - default: - return theme.colors.lightGrayContainer; - } -}; - -export const inputBoxStyle = (theme: Theme, inputType: InputType = 'input') => - css({ - display: 'flex', - justifyContent: 'space-between', - - padding: '0.75rem 1rem', - borderRadius: '1rem', - backgroundColor: inputBoxBackgroundColorByInputType(theme, inputType), - }); - -export const inputStyle = (theme: Theme) => - css( - { - display: 'flex', - width: '100%', - color: theme.colors.black, - - '&:placeholder': { - color: theme.colors.gray, - }, - }, - theme.typography.body, - ); diff --git a/HDesign/src/components/Input/Input.tsx b/HDesign/src/components/Input/Input.tsx deleted file mode 100644 index 4e8ac6e5d..000000000 --- a/HDesign/src/components/Input/Input.tsx +++ /dev/null @@ -1,30 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import React, {forwardRef, useImperativeHandle, useRef} from 'react'; - -import IconButton from '@components/IconButton/IconButton'; -import {InputProps} from '@components/Input/Input.type'; -import {inputBoxStyle, inputStyle} from '@components/Input/Input.style'; -import {useInput} from '@components/Input/useInput'; - -import {useTheme} from '@theme/HDesignProvider'; - -export const Input: React.FC<InputProps> = forwardRef<HTMLInputElement, InputProps>(function Input( - {value: propsValue, onChange, inputType, ...htmlProps}: InputProps, - ref, -) { - const {theme} = useTheme(); - const inputRef = useRef<HTMLInputElement>(null); - - useImperativeHandle(ref, () => inputRef.current!); - - const {value, handleChange, handleClickDelete} = useInput({propsValue, onChange, inputRef}); - - return ( - <div css={inputBoxStyle(theme, inputType)}> - <input css={inputStyle(theme)} ref={inputRef} value={value} onChange={handleChange} {...htmlProps} /> - {value && <IconButton iconType="inputDelete" onClick={handleClickDelete} />} - </div> - ); -}); - -export default Input; diff --git a/HDesign/src/components/Input/Input.type.ts b/HDesign/src/components/Input/Input.type.ts deleted file mode 100644 index b2f2fc827..000000000 --- a/HDesign/src/components/Input/Input.type.ts +++ /dev/null @@ -1,15 +0,0 @@ -import {Theme} from '@theme/theme.type'; - -export interface InputStyleProps { - theme?: Theme; -} - -export type InputType = 'input' | 'search'; - -export interface InputCustomProps { - inputType?: InputType; -} - -export type InputOptionProps = InputStyleProps & InputCustomProps; - -export type InputProps = React.ComponentProps<'input'> & InputOptionProps; diff --git a/HDesign/src/components/Input/useInput.ts b/HDesign/src/components/Input/useInput.ts deleted file mode 100644 index af4892964..000000000 --- a/HDesign/src/components/Input/useInput.ts +++ /dev/null @@ -1,36 +0,0 @@ -import {RefObject, useEffect, useState} from 'react'; - -interface UseInputProps<T> { - propsValue: T; - onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void; - inputRef: RefObject<HTMLInputElement>; -} - -export const useInput = <T>({propsValue, onChange, inputRef}: UseInputProps<T>) => { - const [value, setValue] = useState(propsValue || ''); - - useEffect(() => { - setValue(propsValue || ''); - }, [propsValue]); - - const handleClickDelete = () => { - setValue(''); - - if (inputRef.current) { - inputRef.current.focus(); - } - - if (onChange) { - onChange({target: {value: ''}} as React.ChangeEvent<HTMLInputElement>); - } - }; - - const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { - setValue(e.target.value); - if (onChange) { - onChange(e); - } - }; - - return {value, handleChange, handleClickDelete}; -}; diff --git a/HDesign/src/components/Search/Search.stories.tsx b/HDesign/src/components/Search/Search.stories.tsx deleted file mode 100644 index f4cd6d567..000000000 --- a/HDesign/src/components/Search/Search.stories.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import type {Meta, StoryObj} from '@storybook/react'; - -import React from 'react'; - -import React from 'react'; - -import Search from '@components/Search/Search'; - -const meta = { - title: 'Components/Search', - component: Search, - tags: ['autodocs'], - parameters: { - // layout: 'centered', - }, - argTypes: { - value: { - description: '', - control: {type: 'text'}, - }, - inputType: { - control: {type: 'radio'}, - }, - }, - args: { - disabled: false, - placeholder: 'placeholder', - searchTerms: ['todari', 'cookie'], - setState: keyword => console.log(keyword), - }, -} satisfies Meta<typeof Search>; - -export default meta; - -type Story = StoryObj<typeof meta>; - -export const Playground: Story = {}; diff --git a/HDesign/src/components/Search/Search.style.ts b/HDesign/src/components/Search/Search.style.ts deleted file mode 100644 index 230cf3e8e..000000000 --- a/HDesign/src/components/Search/Search.style.ts +++ /dev/null @@ -1,40 +0,0 @@ -import {css} from '@emotion/react'; - -import {Theme} from '@/theme/theme.type'; - -export const searchStyle = css({ - position: 'relative', - - width: '100%', -}); - -export const searchTermsStyle = (theme: Theme) => - css({ - position: 'absolute', - top: '3.5rem', - - width: 'calc(100% - 2rem)', - margin: '0 1rem', - padding: '0.5rem 0', - - borderRadius: '1rem', - - backgroundColor: theme.colors.white, - }); - -export const searchTermStyle = (theme: Theme) => - css( - { - width: '100%', - padding: '0.5rem 1rem', - - color: theme.colors.onTertiary, - - '&:hover': { - borderRadius: '0.5rem', - - backgroundColor: theme.colors.lightGrayContainer, - }, - }, - theme.typography.body, - ); diff --git a/HDesign/src/components/Search/Search.tsx b/HDesign/src/components/Search/Search.tsx deleted file mode 100644 index cecdffa52..000000000 --- a/HDesign/src/components/Search/Search.tsx +++ /dev/null @@ -1,44 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import Flex from '@components/Flex/Flex'; - -import {useTheme} from '@theme/HDesignProvider'; - -import Input from '../Input/Input'; -import {InputProps} from '../Input/Input.type'; - -import {searchStyle, searchTermsStyle, searchTermStyle} from './Search.style'; -import useSearch from './useSearch'; - -export interface SearchProps extends InputProps { - searchTerms: string[]; - setState: React.Dispatch<React.SetStateAction<string>>; -} - -const Search: React.FC<SearchProps> = ({searchTerms, setState, ...inputProps}: SearchProps) => { - const {theme} = useTheme(); - const {value, showSearchTerms, handleOnChange, handleOnClick, filterSearchTerms} = useSearch({ - searchTerms, - setState, - }); - - return ( - <fieldset css={searchStyle}> - <Input inputType="search" value={value} onChange={handleOnChange} {...inputProps} /> - {showSearchTerms && ( - <ul css={searchTermsStyle(theme)}> - <Flex flexDirection="column" gap="0.5rem"> - {filterSearchTerms(value).map((searchTerm, index) => ( - <li key={`${searchTerm}-${index}`}> - <button type="button" css={searchTermStyle(theme)} onClick={() => handleOnClick(searchTerm)}> - {searchTerm} - </button> - </li> - ))} - </Flex> - </ul> - )} - </fieldset> - ); -}; - -export default Search; diff --git a/HDesign/src/components/Search/useSearch.ts b/HDesign/src/components/Search/useSearch.ts deleted file mode 100644 index fbb9cf4c3..000000000 --- a/HDesign/src/components/Search/useSearch.ts +++ /dev/null @@ -1,39 +0,0 @@ -import {useState} from 'react'; - -interface UseSearchProps { - searchTerms: string[]; - setState: React.Dispatch<React.SetStateAction<string>>; -} - -const useSearch = ({searchTerms, setState}: UseSearchProps) => { - const [value, setValue] = useState(''); - const [showSearchTerms, setShowSearchTerms] = useState(false); - - const handleOnClick = (searchTerm: string) => { - setValue(searchTerm); - setState(searchTerm); - setShowSearchTerms(false); - }; - - const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>) => { - const {value} = event.target; - setValue(value); - setShowSearchTerms(value.trim() !== '' && filterSearchTerms(value).length !== 0); - }; - - const filterSearchTerms = (keyword: string) => { - if (keyword.trim() === '') return []; - - return searchTerms.filter(terms => terms.toLocaleLowerCase().indexOf(keyword.toLocaleLowerCase()) > -1); - }; - - return { - value, - showSearchTerms, - handleOnClick, - handleOnChange, - filterSearchTerms, - }; -}; - -export default useSearch; diff --git a/HDesign/src/components/StepItem/StepItem.stories.tsx b/HDesign/src/components/StepItem/StepItem.stories.tsx deleted file mode 100644 index 3a81c38f6..000000000 --- a/HDesign/src/components/StepItem/StepItem.stories.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import type {Meta, StoryObj} from '@storybook/react'; - -import StepItem from '@components/StepItem/StepItem'; - -const meta = { - title: 'Components/StepItem', - component: StepItem, - tags: ['autodocs'], - parameters: { - // layout: 'centered', - }, - argTypes: { - name: { - description: '', - control: {type: 'text'}, - }, - personCount: { - description: '', - control: {type: 'number'}, - }, - bills: { - description: '', - control: {type: 'object'}, - }, - }, - args: { - name: '으랏차차', - personCount: 8, - bills: [ - { - name: '뽕나무쟁이', - price: 150000, - }, - { - name: '인생네컷', - price: 12000, - }, - ], - }, -} satisfies Meta<typeof StepItem>; - -export default meta; - -type Story = StoryObj<typeof meta>; - -export const Playground: Story = {}; diff --git a/HDesign/src/components/StepItem/StepItem.style.ts b/HDesign/src/components/StepItem/StepItem.style.ts deleted file mode 100644 index 0258b47a4..000000000 --- a/HDesign/src/components/StepItem/StepItem.style.ts +++ /dev/null @@ -1,34 +0,0 @@ -import {css} from '@emotion/react'; - -import {Theme} from '@/theme/theme.type'; - -export const stepItemStyle = (theme: Theme) => - css({ - display: 'flex', - flexDirection: 'column', - gap: '0.5rem', - padding: '0.5rem', - borderRadius: '0.75rem', - backgroundColor: theme.colors.white, - }); - -export const nameStyle = (theme: Theme) => - css({ - color: theme.colors.black, - }); - -export const personCountStyle = (theme: Theme) => - css({ - color: theme.colors.gray, - textDecoration: 'underline', - }); - -export const totalTitleStyle = (theme: Theme) => - css({ - color: theme.colors.black, - }); - -export const totalAmountStyle = (theme: Theme) => - css({ - color: theme.colors.gray, - }); diff --git a/HDesign/src/components/StepItem/StepItem.tsx b/HDesign/src/components/StepItem/StepItem.tsx deleted file mode 100644 index 52e79d863..000000000 --- a/HDesign/src/components/StepItem/StepItem.tsx +++ /dev/null @@ -1,43 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import {useTheme} from '@/theme/HDesignProvider'; - -import Text from '../Text/Text'; -import BillItem from '../BillItem/BillItem'; -import {BillItemCustomProps} from '../BillItem/BillItem.type'; -import Flex from '../Flex/Flex'; - -import {nameStyle, personCountStyle, stepItemStyle, totalAmountStyle, totalTitleStyle} from './StepItem.style'; -import {StepItemCustomProps} from './StepItem.type'; - -export const StepItem: React.FC<StepItemCustomProps> = ({ - name = '', - personCount = 0, - bills, - ...htmlProps -}: StepItemCustomProps) => { - const {theme} = useTheme(); - return ( - <div css={stepItemStyle(theme)} {...htmlProps}> - <Flex justifyContent="spaceBetween" paddingInline="0.5rem"> - <Text css={nameStyle(theme)} size="captionBold"> - {name} - </Text> - <Text css={personCountStyle(theme)} size="caption"> - {personCount}명 - </Text> - </Flex> - {bills.map((props: BillItemCustomProps) => ( - <BillItem {...props} /> - ))} - <Flex justifyContent="spaceBetween" paddingInline="0.5rem"> - <Text css={totalTitleStyle(theme)} size="captionBold"> - 총액 - </Text> - <Text css={totalAmountStyle(theme)} size="caption"> - {bills.reduce((acc, prev) => acc + (prev.price ?? 0), 0).toLocaleString('ko-kr')}원 - </Text> - </Flex> - </div> - ); -}; -export default StepItem; diff --git a/HDesign/src/components/StepItem/StepItem.type.ts b/HDesign/src/components/StepItem/StepItem.type.ts deleted file mode 100644 index 516b7b675..000000000 --- a/HDesign/src/components/StepItem/StepItem.type.ts +++ /dev/null @@ -1,13 +0,0 @@ -import {BillItemCustomProps} from '../BillItem/BillItem.type'; - -export interface StepItemStyleProps {} - -export interface StepItemCustomProps { - name: string; - personCount: number; - bills: BillItemCustomProps[]; -} - -export type StepItemOptionProps = StepItemStyleProps & StepItemCustomProps; - -export type StepItemProps = React.ComponentProps<'div'> & StepItemOptionProps; diff --git a/HDesign/src/components/Switch/Switch.stories.tsx b/HDesign/src/components/Switch/Switch.stories.tsx deleted file mode 100644 index a3558754a..000000000 --- a/HDesign/src/components/Switch/Switch.stories.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import type {Meta, StoryObj} from '@storybook/react'; - -import Switch from '@components/Switch/Switch'; - -const meta = { - title: 'Components/Switch', - component: Switch, - tags: ['autodocs'], - parameters: { - layout: 'centered', - }, - argTypes: { - value: { - description: '', - control: {type: 'select', options: ['홈', '관리']}, - }, - values: { - description: '', - }, - onChange: { - description: '', - }, - }, - args: { - value: '홈', - values: ['홈', '관리'], - onChange: value => alert(`${value} 선택됨`), - }, -} satisfies Meta<typeof Switch>; - -export default meta; - -type Story = StoryObj<typeof meta>; - -export const Playground: Story = {}; diff --git a/HDesign/src/components/Switch/Switch.style.ts b/HDesign/src/components/Switch/Switch.style.ts deleted file mode 100644 index d88c18748..000000000 --- a/HDesign/src/components/Switch/Switch.style.ts +++ /dev/null @@ -1,6 +0,0 @@ -import {css} from '@emotion/react'; - -export const switchContainerStyle = css({ - display: 'flex', - gap: '0.75rem', -}); diff --git a/HDesign/src/components/Switch/Switch.tsx b/HDesign/src/components/Switch/Switch.tsx deleted file mode 100644 index 4a1275185..000000000 --- a/HDesign/src/components/Switch/Switch.tsx +++ /dev/null @@ -1,24 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import TextButton from '../TextButton/TextButton'; - -import {switchContainerStyle} from './Switch.style'; -import {SwitchProps} from './Switch.type'; - -function Switch({value, values, onChange}: SwitchProps) { - return ( - <div css={switchContainerStyle}> - {values.map((item, index) => ( - <TextButton - key={`${index}_${item}`} - textColor={value === item ? 'black' : 'gray'} - textSize="bodyBold" - onClick={() => onChange(values[index])} - > - {item} - </TextButton> - ))} - </div> - ); -} - -export default Switch; diff --git a/HDesign/src/components/Switch/Switch.type.ts b/HDesign/src/components/Switch/Switch.type.ts deleted file mode 100644 index 7e0d31d0f..000000000 --- a/HDesign/src/components/Switch/Switch.type.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface SwitchProps { - value: string; - values: string[]; - onChange: (value: string) => void; -} diff --git a/HDesign/src/components/Tabs/Tab.tsx b/HDesign/src/components/Tabs/Tab.tsx deleted file mode 100644 index 2a79c1b78..000000000 --- a/HDesign/src/components/Tabs/Tab.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import {TabProps} from './Tab.type'; - -const Tab: React.FC<TabProps> = () => { - return <></>; -}; - -export default Tab; diff --git a/HDesign/src/components/Tabs/Tab.type.ts b/HDesign/src/components/Tabs/Tab.type.ts deleted file mode 100644 index 6b9e4972e..000000000 --- a/HDesign/src/components/Tabs/Tab.type.ts +++ /dev/null @@ -1,16 +0,0 @@ -import {FlexProps} from '../Flex/Flex.type'; - -export interface TabProps { - label: string; - content: React.ReactNode; -} - -export interface TabsCustomProps { - children: React.ReactElement<TabProps>[]; -} - -export interface TabsStyleProps { - tabsContainerStyle?: FlexProps; -} - -export type TabsProps = TabsCustomProps & TabsStyleProps; diff --git a/HDesign/src/components/Tabs/Tabs.stories.tsx b/HDesign/src/components/Tabs/Tabs.stories.tsx deleted file mode 100644 index 6d03a7406..000000000 --- a/HDesign/src/components/Tabs/Tabs.stories.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import type {Meta, StoryObj} from '@storybook/react'; - -import React from 'react'; - -import Tabs from '@/components/Tabs/Tabs'; - -import Tab from './Tab'; - -const meta = { - title: 'Components/Tabs', - component: Tabs, - tags: ['autodocs'], - parameters: { - // layout: 'centered', - }, - args: { - children: [ - <Tab label="전체 지출 내역" content={<div>없지롱</div>} />, - <Tab label="참여자 별 정산" content={<div>있지롱</div>} />, - ], - tabsContainerStyle: { - gap: '0.5rem', - }, - }, -} satisfies Meta<typeof Tabs>; - -export default meta; - -type Story = StoryObj<typeof meta>; - -export const Playground: Story = {}; diff --git a/HDesign/src/components/Tabs/Tabs.style.ts b/HDesign/src/components/Tabs/Tabs.style.ts deleted file mode 100644 index a4a12f630..000000000 --- a/HDesign/src/components/Tabs/Tabs.style.ts +++ /dev/null @@ -1,51 +0,0 @@ -import {css} from '@emotion/react'; - -import {Theme} from '@/theme/theme.type'; - -export const tabListStyle = (theme: Theme) => - css({ - position: 'relative', - - backgroundColor: theme.colors.white, - - cursor: 'pointer', - - '&::after': { - position: 'absolute', - left: 0, - bottom: 0, - zIndex: 1, - - width: '100%', - height: '0.0625rem', - - backgroundColor: theme.colors.gray, - - content: '""', - }, - }); - -export const tabItemStyle = css({ - flex: 1, - - textAlign: 'center', -}); - -export const tabTextStyle = (theme: Theme, selected: boolean) => - css({ - color: selected ? theme.colors.onTertiary : theme.colors.gray, - }); - -export const indicatorStyle = (theme: Theme, leftPosition: string, tabLength: number) => - css({ - position: 'absolute', - left: leftPosition, - bottom: 0, - zIndex: 2, - - width: `calc(100% / ${tabLength})`, - height: '0.125rem', - - backgroundColor: theme.colors.onSecondary, - transition: 'left 0.3s', - }); diff --git a/HDesign/src/components/Tabs/Tabs.tsx b/HDesign/src/components/Tabs/Tabs.tsx deleted file mode 100644 index 0245b5ba7..000000000 --- a/HDesign/src/components/Tabs/Tabs.tsx +++ /dev/null @@ -1,53 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import React, {useState} from 'react'; -import {css} from '@emotion/react'; - -import {useTheme} from '@theme/HDesignProvider'; - -import Text from '../Text/Text'; -import Flex from '../Flex/Flex'; - -import {tabListStyle, indicatorStyle, tabItemStyle, tabTextStyle} from './Tabs.style'; -import {TabsProps} from './Tab.type'; - -const Tabs: React.FC<TabsProps> = ({children, tabsContainerStyle}) => { - const {theme} = useTheme(); - const [activeTabIndex, setActiveTabIndex] = useState(0); - - const isActive = (index: number) => activeTabIndex === index; - const tabItemCount = children.length; - - return ( - <Flex flexDirection="column" {...tabsContainerStyle}> - <ul role="tablist" css={tabListStyle(theme)}> - <Flex justifyContent="spaceBetween" alignItems="center" padding="0.5rem"> - {children.map((tabItem, index) => ( - <li - key={tabItem.props.label} - role="tab" - id={`tab-${tabItem.props.label}`} - css={tabItemStyle} - aria-selected={isActive(index)} - onClick={() => setActiveTabIndex(index)} - aria-controls={`tabpanel-${tabItem.props.label}`} - > - <Text css={tabTextStyle(theme, isActive(index))} size={isActive(index) ? 'bodyBold' : 'body'}> - {tabItem.props.label} - </Text> - </li> - ))} - <div css={indicatorStyle(theme, `${(activeTabIndex * 100) / tabItemCount}%`, tabItemCount)} /> - </Flex> - </ul> - <section - role="tabpanel" - id={`tabpanel-${children[activeTabIndex].props.label}`} - aria-labelledby={`tab-${children[activeTabIndex].props.label}}`} - > - {children[activeTabIndex].props.content} - </section> - </Flex> - ); -}; - -export default Tabs; diff --git a/HDesign/src/components/Text/Text.stories.tsx b/HDesign/src/components/Text/Text.stories.tsx deleted file mode 100644 index 5e5ec2287..000000000 --- a/HDesign/src/components/Text/Text.stories.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import type {Meta, StoryObj} from '@storybook/react'; - -import Text from '@components/Text/Text'; - -const meta = { - title: 'Components/Text', - component: Text, - tags: ['autodocs'], - parameters: { - layout: 'centered', - }, - argTypes: { - size: { - description: '', - control: {type: 'select'}, - options: [ - 'head', - 'title', - 'subTitle', - 'bodyBold', - 'body', - 'smallBodyBold', - 'smallBody', - 'caption', - 'captionBold', - 'tiny', - ], - }, - }, - args: { - size: 'body', - children: 'text', - }, -} satisfies Meta<typeof Text>; - -export default meta; - -type Story = StoryObj<typeof meta>; - -export const Playground: Story = {}; diff --git a/HDesign/src/components/Text/Text.style.ts b/HDesign/src/components/Text/Text.style.ts deleted file mode 100644 index 8767cdb0f..000000000 --- a/HDesign/src/components/Text/Text.style.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type {TextProps} from './Text.type'; - -import {css} from '@emotion/react'; - -// TODO: (@todari) themeProvider 이용하도록 변경 -import TYPOGRAPHY from '@token/typography'; - -export const getSizeStyling = (size: Required<TextProps>['size']) => { - const style = { - head: css(TYPOGRAPHY.head), - title: css(TYPOGRAPHY.title), - subTitle: css(TYPOGRAPHY.subTitle), - bodyBold: css(TYPOGRAPHY.bodyBold), - body: css(TYPOGRAPHY.body), - smallBodyBold: css(TYPOGRAPHY.smallBodyBold), - smallBody: css(TYPOGRAPHY.smallBody), - captionBold: css(TYPOGRAPHY.captionBold), - caption: css(TYPOGRAPHY.caption), - tiny: css(TYPOGRAPHY.tiny), - }; - - return style[size]; -}; diff --git a/HDesign/src/components/Text/Text.tsx b/HDesign/src/components/Text/Text.tsx deleted file mode 100644 index e0e2a8ec8..000000000 --- a/HDesign/src/components/Text/Text.tsx +++ /dev/null @@ -1,16 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import type {TextProps} from '@components/Text/Text.type'; - -import React from 'react'; - -import {getSizeStyling} from './Text.style'; - -const Text: React.FC<TextProps> = ({size = 'body', children, ...attributes}: TextProps) => { - return ( - <p css={getSizeStyling(size)} {...attributes}> - {children} - </p> - ); -}; - -export default Text; diff --git a/HDesign/src/components/Text/Text.type.ts b/HDesign/src/components/Text/Text.type.ts deleted file mode 100644 index db75b09be..000000000 --- a/HDesign/src/components/Text/Text.type.ts +++ /dev/null @@ -1,21 +0,0 @@ -export type TextSize = - | 'head' - | 'title' - | 'subTitle' - | 'body' - | 'smallBody' - | 'caption' - | 'tiny' - | 'bodyBold' - | 'smallBodyBold' - | 'captionBold'; - -export interface TextStyleProps { - size?: TextSize; -} - -export interface TextCustomProps {} - -export type TextOptionProps = TextStyleProps & TextCustomProps; - -export type TextProps = React.ComponentProps<'p'> & TextOptionProps; diff --git a/HDesign/src/components/TextButton/TextButton.stories.tsx b/HDesign/src/components/TextButton/TextButton.stories.tsx deleted file mode 100644 index 9873df3f4..000000000 --- a/HDesign/src/components/TextButton/TextButton.stories.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import type {Meta, StoryObj} from '@storybook/react'; - -import TextButton from '@components/TextButton/TextButton'; - -const meta = { - title: 'Components/TextButton', - component: TextButton, - tags: ['autodocs'], - parameters: { - layout: 'centered', - }, - argTypes: { - textSize: { - description: '', - control: {type: 'select'}, - options: [ - 'head', - 'title', - 'subTitle', - 'bodyBold', - 'body', - 'smallBodyBold', - 'smallBody', - 'caption', - 'captionBold', - 'tiny', - ], - }, - textColor: { - description: '', - control: {type: 'select'}, - options: ['black', 'gray'], - }, - children: { - description: '', - control: {type: 'text'}, - }, - }, - args: { - textColor: 'black', - textSize: 'bodyBold', - children: '뒤로가기', - }, -} satisfies Meta<typeof TextButton>; - -export default meta; - -type Story = StoryObj<typeof meta>; - -export const Playground: Story = {}; diff --git a/HDesign/src/components/TextButton/TextButton.style.ts b/HDesign/src/components/TextButton/TextButton.style.ts deleted file mode 100644 index 6777b1eed..000000000 --- a/HDesign/src/components/TextButton/TextButton.style.ts +++ /dev/null @@ -1,15 +0,0 @@ -import {css} from '@emotion/react'; - -import {Theme} from '@/theme/theme.type'; - -import {TextColor} from './TextButton.type'; - -interface TextButtonStyleProps { - textColor: TextColor; - theme: Theme; -} - -export const textButtonStyle = ({textColor, theme}: TextButtonStyleProps) => - css({ - color: theme.colors[textColor], - }); diff --git a/HDesign/src/components/TextButton/TextButton.tsx b/HDesign/src/components/TextButton/TextButton.tsx deleted file mode 100644 index 9d857c38d..000000000 --- a/HDesign/src/components/TextButton/TextButton.tsx +++ /dev/null @@ -1,26 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import {forwardRef} from 'react'; - -import {useTheme} from '@/theme/HDesignProvider'; - -import Text from '../Text/Text'; - -import {TextButtonProps} from './TextButton.type'; -import {textButtonStyle} from './TextButton.style'; - -export const TextButton: React.FC<TextButtonProps> = forwardRef<HTMLButtonElement, TextButtonProps>(function Button( - {textColor, textSize, children, ...htmlProps}: TextButtonProps, - ref, -) { - const {theme} = useTheme(); - - return ( - <button ref={ref} {...htmlProps}> - <Text size={textSize} css={textButtonStyle({textColor, theme})}> - {children} - </Text> - </button> - ); -}); - -export default TextButton; diff --git a/HDesign/src/components/TextButton/TextButton.type.ts b/HDesign/src/components/TextButton/TextButton.type.ts deleted file mode 100644 index 0299d89b9..000000000 --- a/HDesign/src/components/TextButton/TextButton.type.ts +++ /dev/null @@ -1,15 +0,0 @@ -import {TextSize} from '../Text/Text.type'; - -export type TextColor = 'black' | 'gray'; - -export interface TextButtonStyleProps { - textColor: TextColor; -} - -export interface TextButtonCustomProps { - textSize: TextSize; -} - -export type TextButtonOptionProps = TextButtonStyleProps & TextButtonCustomProps; - -export type TextButtonProps = React.ComponentProps<'button'> & TextButtonOptionProps; diff --git a/HDesign/src/components/Title/Title.stories.tsx b/HDesign/src/components/Title/Title.stories.tsx deleted file mode 100644 index 3973779db..000000000 --- a/HDesign/src/components/Title/Title.stories.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import type {Meta, StoryObj} from '@storybook/react'; - -import Title from '@components/Title/Title'; - -const meta = { - title: 'Components/Title', - component: Title, - tags: ['autodocs'], - parameters: { - layout: 'centered', - }, - argTypes: { - title: { - description: '', - control: {type: 'text'}, - }, - description: { - description: '', - control: {type: 'text'}, - }, - price: { - description: '', - control: {type: 'number'}, - }, - }, - args: { - title: '페이지 제목이에요', - description: '이곳에는 페이지 설명이 들어가요. 페이지에 대한 설명을 자세하게 적어주면 좋아요 :)', - price: 100000, - }, -} satisfies Meta<typeof Title>; - -export default meta; - -type Story = StoryObj<typeof meta>; - -export const Playground: Story = {}; diff --git a/HDesign/src/components/Title/Title.style.ts b/HDesign/src/components/Title/Title.style.ts deleted file mode 100644 index 700128c02..000000000 --- a/HDesign/src/components/Title/Title.style.ts +++ /dev/null @@ -1,39 +0,0 @@ -import {css} from '@emotion/react'; - -import {Theme} from '@theme/theme.type'; - -export const titleContainerStyle = (theme: Theme) => - css({ - display: 'flex', - flexDirection: 'column', - width: '100%', - gap: '0.5rem', - backgroundColor: theme.colors.white, - padding: '1rem', - }); - -export const titleStyle = (theme: Theme) => - css({ - color: theme.colors.black, - }); - -export const descriptionStyle = (theme: Theme) => - css({ - color: theme.colors.darkGray, - }); - -export const priceContainerStyle = css({ - display: 'flex', - justifyContent: 'space-between', - alignItems: 'end', -}); - -export const priceTitleStyle = (theme: Theme) => - css({ - color: theme.colors.gray, - }); - -export const priceStyle = (theme: Theme) => - css({ - color: theme.colors.black, - }); diff --git a/HDesign/src/components/Title/Title.tsx b/HDesign/src/components/Title/Title.tsx deleted file mode 100644 index ee7847a0e..000000000 --- a/HDesign/src/components/Title/Title.tsx +++ /dev/null @@ -1,39 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import Text from '@components/Text/Text'; -import { - descriptionStyle, - priceContainerStyle, - priceStyle, - priceTitleStyle, - titleContainerStyle, - titleStyle, -} from '@components/Title/Title.style'; -import {TitleProps} from '@components/Title/Title.type'; - -import {useTheme} from '@theme/HDesignProvider'; - -export const Title: React.FC<TitleProps> = ({title, description, price}: TitleProps) => { - const {theme} = useTheme(); - return ( - <div css={titleContainerStyle(theme)}> - <Text css={titleStyle(theme)} size="subTitle"> - {title} - </Text> - {description && ( - <Text css={descriptionStyle(theme)} size="caption"> - {description} - </Text> - )} - {price !== undefined && ( - <div css={priceContainerStyle}> - <Text css={priceTitleStyle(theme)} size="caption"> - 전체 지출 금액 - </Text> - <Text css={priceStyle(theme)}>{price.toLocaleString('ko-kr')}원</Text> - </div> - )} - </div> - ); -}; - -export default Title; diff --git a/HDesign/src/components/Title/Title.type.ts b/HDesign/src/components/Title/Title.type.ts deleted file mode 100644 index 4b12f23b2..000000000 --- a/HDesign/src/components/Title/Title.type.ts +++ /dev/null @@ -1,11 +0,0 @@ -export interface TitleStyleProps {} - -export interface TitleCustomProps { - title: string; - description?: string; - price?: number; -} - -export type TitleOptionProps = TitleStyleProps & TitleCustomProps; - -export type TitleProps = React.ComponentProps<'div'> & TitleOptionProps; diff --git a/HDesign/src/components/TopNav/Back.tsx b/HDesign/src/components/TopNav/Back.tsx deleted file mode 100644 index cfb55e24d..000000000 --- a/HDesign/src/components/TopNav/Back.tsx +++ /dev/null @@ -1,17 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import React from 'react'; -import {useNavigate} from 'react-router-dom'; - -import TextButton from '@components/TextButton/TextButton'; - -function Back() { - const navigate = useNavigate(); - - return ( - <TextButton onClick={() => navigate(-1)} textSize="bodyBold" textColor="gray"> - 뒤로가기 - </TextButton> - ); -} - -export default Back; diff --git a/HDesign/src/components/TopNav/TopNav.stories.tsx b/HDesign/src/components/TopNav/TopNav.stories.tsx deleted file mode 100644 index 0c96161a5..000000000 --- a/HDesign/src/components/TopNav/TopNav.stories.tsx +++ /dev/null @@ -1,50 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import type {Meta, StoryObj} from '@storybook/react'; - -import React from 'react'; -import {reactRouterParameters, withRouter} from 'storybook-addon-react-router-v6'; - -import TopNav from '@components/TopNav/TopNav'; - -import Switch from '../Switch/Switch'; - -import Back from './Back'; - -const meta = { - title: 'Components/TopNav', - component: TopNav, - tags: ['autodocs'], - decorators: [withRouter], - parameters: { - reactRouter: reactRouterParameters({ - location: { - pathParams: { - eventId: '123123', - }, - }, - routing: {path: '/event/:eventId/home'}, - }), - // layout: 'centered', - }, - argTypes: { - children: { - description: '', - control: {type: 'select'}, - options: ['Back', 'Switch', 'Any'], - mapping: { - Back: <Back />, - Switch: <Switch values={['홈', '관리']} value="홈" onChange={value => console.log(value)} />, - Any: <div />, - }, - }, - }, - args: { - children: 'Back', - }, -} satisfies Meta<typeof TopNav>; - -export default meta; - -type Story = StoryObj<typeof meta>; - -export const Playground: Story = {}; diff --git a/HDesign/src/components/TopNav/TopNav.style.ts b/HDesign/src/components/TopNav/TopNav.style.ts deleted file mode 100644 index 44e7695e7..000000000 --- a/HDesign/src/components/TopNav/TopNav.style.ts +++ /dev/null @@ -1,14 +0,0 @@ -import {css} from '@emotion/react'; - -export const topNavStyle = css({ - display: 'flex', - padding: '0 1rem', - width: '100%', -}); - -export const topNavNonStyle = css({ - display: 'flex', - padding: '0 1rem', - width: '100%', - height: '1.5rem', -}); diff --git a/HDesign/src/components/TopNav/TopNav.tsx b/HDesign/src/components/TopNav/TopNav.tsx deleted file mode 100644 index 643cd5e3b..000000000 --- a/HDesign/src/components/TopNav/TopNav.tsx +++ /dev/null @@ -1,20 +0,0 @@ -/** @jsxImportSource @emotion/react */ -import React from 'react'; - -import Switch from '@components/Switch/Switch'; - -import {topNavNonStyle, topNavStyle} from './TopNav.style'; -import Back from './Back'; - -const TopNav: React.FC<React.PropsWithChildren> = ({children}) => { - const hasBack = React.Children.toArray(children).some(child => React.isValidElement(child) && child.type === Back); - const hasSwitch = React.Children.toArray(children).some( - child => React.isValidElement(child) && child.type === Switch, - ); - - const isExistNav = hasBack || hasSwitch; - - return <div css={isExistNav ? topNavStyle : topNavNonStyle}>{children}</div>; -}; - -export default TopNav; diff --git a/HDesign/src/index.tsx b/HDesign/src/index.tsx deleted file mode 100644 index e0b6e6fee..000000000 --- a/HDesign/src/index.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import BillItem from '@components/BillItem/BillItem'; -import BottomSheet from '@components/BottomSheet/BottomSheet'; -import Button from '@components/Button/Button'; -import DragHandleItem from '@components/DragHandleItem/DragHandleItem'; -import ExpenseList from '@components/ExpenseList/ExpenseList'; -import FixedButton from '@components/FixedButton/FixedButton'; -import Flex from '@components/Flex/Flex'; -import IconButton from '@components/IconButton/IconButton'; -import InOutItem from '@components/InOutItem/InOutItem'; -import Input from '@components/Input/Input'; -import Search from '@components/Search/Search'; -import StepItem from '@components/StepItem/StepItem'; -import Switch from '@components/Switch/Switch'; -import Tabs from '@/components/Tabs/Tabs'; -import Text from '@components/Text/Text'; -import TextButton from '@components/TextButton/TextButton'; -import Title from '@components/Title/Title'; -import TopNav from '@components/TopNav/TopNav'; -import {MainLayout} from '@layouts/MainLayout'; -import {ContentLayout} from '@layouts/ContentLayout'; - -import {HDesignProvider} from '@theme/HDesignProvider'; - -import Tab from './components/Tabs/Tab'; -import Back from './components/TopNav/Back'; - -export { - Back, - BillItem, - BottomSheet, - Button, - DragHandleItem, - ExpenseList, - FixedButton, - Flex, - IconButton, - InOutItem, - Input, - Search, - StepItem, - Switch, - Tab, - Tabs, - Text, - TextButton, - Title, - TopNav, - MainLayout, - ContentLayout, - HDesignProvider, -}; diff --git a/HDesign/src/layouts/ContentLayout.tsx b/HDesign/src/layouts/ContentLayout.tsx deleted file mode 100644 index 757a580ec..000000000 --- a/HDesign/src/layouts/ContentLayout.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import {PropsWithChildren} from 'react'; - -import {Flex} from '..'; - -type ContentLayoutBackground = 'white' | 'gray'; - -interface ContentLayoutProps extends PropsWithChildren { - backgroundColor?: ContentLayoutBackground; -} - -export function ContentLayout({backgroundColor, children}: ContentLayoutProps) { - return ( - <Flex - backgroundColor={backgroundColor} - justifyContent="flexStart" - flexDirection="column" - padding="0 1rem" - gap="1rem" - width="100%" - height="100%" - > - {children} - </Flex> - ); -} diff --git a/HDesign/src/layouts/MainLayout.tsx b/HDesign/src/layouts/MainLayout.tsx deleted file mode 100644 index b64e3c546..000000000 --- a/HDesign/src/layouts/MainLayout.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import {PropsWithChildren} from 'react'; - -import {Flex} from '..'; - -type MainLayoutBackground = 'white' | 'gray'; - -interface MainLayoutProps extends PropsWithChildren { - backgroundColor?: MainLayoutBackground; -} - -export function MainLayout({backgroundColor, children}: MainLayoutProps) { - return ( - <Flex - backgroundColor={backgroundColor} - justifyContent="flexStart" - flexDirection="column" - padding="1rem 0 0 0" - gap="1rem" - width="100%" - height="100%" - > - {children} - </Flex> - ); -} diff --git a/HDesign/src/theme/GlobalStyle.ts b/HDesign/src/theme/GlobalStyle.ts deleted file mode 100644 index 0c1670b07..000000000 --- a/HDesign/src/theme/GlobalStyle.ts +++ /dev/null @@ -1,119 +0,0 @@ -import {css} from '@emotion/react'; - -export const GlobalStyle = css` - *:where(:not(html, iframe, canvas, img, svg, video, audio):not(svg *, symbol *)) { - all: unset; - display: revert; - } - - /* Preferred box-sizing value */ - *, - *::before, - *::after { - box-sizing: border-box; - } - - /* Fix mobile Safari increase font-size on landscape mode */ - html { - -moz-text-size-adjust: none; - -webkit-text-size-adjust: none; - text-size-adjust: none; - } - - /* Reapply the pointer cursor for anchor tags */ - a, - button { - cursor: revert; - line-height: 0; - } - - /* Remove list styles (bullets/numbers) */ - ol, - ul, - menu, - summary { - list-style: none; - } - - /* Removes spacing between cells in tables */ - table { - border-collapse: collapse; - } - - /* Safari - solving issue when using user-select:none on the <body> text input doesn't working */ - input, - textarea { - -webkit-user-select: auto; - } - - /* Revert the 'white-space' property for textarea elements on Safari */ - textarea { - white-space: revert; - } - - /* Minimum style to allow to style meter element */ - meter { - -webkit-appearance: revert; - appearance: revert; - } - - /* Preformatted text - use only for this feature */ - :where(pre) { - all: revert; - box-sizing: border-box; - } - - /* Fix the feature of 'hidden' attribute. - display: revert; revert to element instead of attribute */ - :where([hidden]) { - display: none; - } - - /* Revert for bug in Chromium browsers - - Fix for the content editable attribute will work properly. - - webkit-user-select: auto; added for Safari in case of using user-select:none on wrapper element */ - :where([contenteditable]:not([contenteditable='false'])) { - -moz-user-modify: read-write; - -webkit-user-modify: read-write; - overflow-wrap: break-word; - -webkit-line-break: after-white-space; - -webkit-user-select: auto; - } - - /* Apply back the draggable feature - exist only in Chromium and Safari */ - :where([draggable='true']) { - -webkit-user-drag: element; - } - - /* Revert Modal native behavior */ - :where(dialog:modal) { - all: revert; - box-sizing: border-box; - } - - /* Remove details summary webkit styles */ - ::-webkit-details-marker { - display: none; - } - - /* Chrome, Safari, Edge, Opera */ - input::-webkit-outer-spin-button, - input::-webkit-inner-spin-button { - -webkit-appearance: none; - margin: 0; - } - - /* Firefox */ - input[type='number'] { - -moz-appearance: textfield; - } - - #root { - display: flex; - justify-content: center; - } - - button { - cursor: pointer; - } -`; diff --git a/HDesign/src/theme/HDesignProvider.tsx b/HDesign/src/theme/HDesignProvider.tsx deleted file mode 100644 index 6c7c571a3..000000000 --- a/HDesign/src/theme/HDesignProvider.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React, {createContext, useContext, useState, ReactNode} from 'react'; -import {Global} from '@emotion/react'; - -import {Theme} from '@theme/theme.type'; -import {GlobalStyle} from '@theme/GlobalStyle'; - -import {COLORS} from '@token/colors'; -import {TYPOGRAPHY} from '@token/typography'; - -interface ThemeContextProps { - theme: Theme; -} - -const defaultTheme: Theme = { - colors: COLORS, - typography: TYPOGRAPHY, -}; - -const ThemeContext = createContext<ThemeContextProps | undefined>(undefined); - -export const HDesignProvider: React.FC<{children: ReactNode}> = ({children}) => { - const [theme, _] = useState<Theme>(defaultTheme); - return ( - <ThemeContext.Provider value={{theme}}> - <Global styles={GlobalStyle} /> - {children} - </ThemeContext.Provider> - ); -}; - -export const useTheme = (): ThemeContextProps => { - const context = useContext(ThemeContext); - if (!context) { - throw new Error('useTheme must be used within a HDesignProvider'); - } - return context; -}; diff --git a/HDesign/src/theme/theme.type.ts b/HDesign/src/theme/theme.type.ts deleted file mode 100644 index dffd961f0..000000000 --- a/HDesign/src/theme/theme.type.ts +++ /dev/null @@ -1,7 +0,0 @@ -import {ColorTokens} from '@token/colors'; -import {TypographyTokens} from '@token/typography'; - -export interface Theme { - colors: ColorTokens; - typography: TypographyTokens; -} diff --git a/HDesign/src/token/colors.ts b/HDesign/src/token/colors.ts deleted file mode 100644 index 01bbf8f02..000000000 --- a/HDesign/src/token/colors.ts +++ /dev/null @@ -1,60 +0,0 @@ -const PRIMITIVE_COLORS = { - white: '#FFFFFF', - purple: { - 50: '#f4e8ff', - 100: '#e0c7fe', - 200: '#cba0fe', - 300: '#b575ff', - 400: '#a350fd', - 500: '#8f2bf3', - 600: '#8425ec', - 700: '#7519e3', - 800: '#6712db', - 900: '#5100cd', - }, - gray: { - 50: '#F9F8FD', - 100: '#F1F0F5', - 200: '#E7E6EB', - 300: '#D6D5DA', - 400: '#B2B1B6', - 500: '#929195', - 600: '#6A696D', - 700: '#56555A', - 800: '#38373B', - 900: '#18171B', - }, -}; - -type Color = string; - -export type ColorKeys = - | 'white' - | 'gray' - | 'darkGray' - | 'black' - | 'primary' - | 'onPrimary' - | 'secondary' - | 'onSecondary' - | 'tertiary' - | 'onTertiary' - | 'grayContainer' - | 'lightGrayContainer'; -export type ColorTokens = Record<ColorKeys, Color>; - -// TODO: (@soha) 대괄호 사용에 대해 논의 -export const COLORS: ColorTokens = { - white: PRIMITIVE_COLORS.white, - gray: PRIMITIVE_COLORS.gray[400], - darkGray: PRIMITIVE_COLORS.gray[500], - black: PRIMITIVE_COLORS.gray[700], - primary: PRIMITIVE_COLORS.purple[300], - onPrimary: PRIMITIVE_COLORS.white, - secondary: PRIMITIVE_COLORS.purple[50], - onSecondary: PRIMITIVE_COLORS.purple[600], - tertiary: PRIMITIVE_COLORS.gray[200], - onTertiary: PRIMITIVE_COLORS.gray[700], - grayContainer: PRIMITIVE_COLORS.gray[100], - lightGrayContainer: PRIMITIVE_COLORS.gray[50], -}; diff --git a/HDesign/src/token/typography.ts b/HDesign/src/token/typography.ts deleted file mode 100644 index c88d61ea9..000000000 --- a/HDesign/src/token/typography.ts +++ /dev/null @@ -1,67 +0,0 @@ -type Typography = Record<string, string>; -export type TypographyTokens = Record<string, Typography>; - -export const TYPOGRAPHY: TypographyTokens = { - head: { - fontFamily: 'Pretendard', - fontSize: '3rem', - lineHeight: '1.5', - fontWeight: '700', - }, - title: { - fontFamily: 'Pretendard', - fontSize: '2rem', - lineHeight: '1.5', - fontWeight: '700', - }, - subTitle: { - fontFamily: 'Pretendard', - fontSize: '1.5rem', - lineHeight: '1.5', - fontWeight: '700', - }, - bodyBold: { - fontFamily: 'Pretendard', - fontSize: '1rem', - lineHeight: '1.5', - fontWeight: '700', - }, - body: { - fontFamily: 'Pretendard', - fontSize: '1rem', - lineHeight: '1.5', - fontWeight: '400', - }, - smallBodyBold: { - fontFamily: 'Pretendard', - fontSize: '0.875rem', - lineHeight: '1.5', - fontWeight: '700', - }, - smallBody: { - fontFamily: 'Pretendard', - fontSize: '0.875rem', - lineHeight: '1.5', - fontWeight: '400', - }, - captionBold: { - fontFamily: 'Pretendard', - fontSize: '0.75rem', - lineHeight: '1.5', - fontWeight: '700', - }, - caption: { - fontFamily: 'Pretendard', - fontSize: '0.75rem', - lineHeight: '1.5', - fontWeight: '400', - }, - tiny: { - fontFamily: 'Pretendard', - fontSize: '0.625rem', - lineHeight: '1.5', - fontWeight: '400', - }, -}; - -export default TYPOGRAPHY; diff --git a/HDesign/src/types/strictPropsWithChildren.ts b/HDesign/src/types/strictPropsWithChildren.ts deleted file mode 100644 index 684fbcc76..000000000 --- a/HDesign/src/types/strictPropsWithChildren.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type StrictPropsWithChildren<P = unknown> = P & { - children: React.ReactNode; -}; diff --git a/HDesign/src/utils/ return str.replace(/([a-z])([A-Z])/changeCamelCaseToKebabCase.ts b/HDesign/src/utils/ return str.replace(/([a-z])([A-Z])/changeCamelCaseToKebabCase.ts deleted file mode 100644 index 2bca7c1b7..000000000 --- a/HDesign/src/utils/ return str.replace(/([a-z])([A-Z])/changeCamelCaseToKebabCase.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const changeCamelCaseToKebabCase = (str: string) => { - return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); -}; diff --git a/HDesign/tsconfig.json b/HDesign/tsconfig.json deleted file mode 100644 index 371b40efe..000000000 --- a/HDesign/tsconfig.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "compilerOptions": { - "sourceMap": true, - "outDir": "./dist", - "target": "ES5", - "skipLibCheck": true, - "module": "commonjs", - "moduleResolution": "node", - "strict": true, - "declaration": true, - "declarationDir": "./dist", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "lib": ["DOM", "DOM.Iterable", "ESNext"], - "jsx": "react-jsx", - "allowJs": true, - "baseUrl": ".", - "paths": { - "@/*": ["src/*"], - "@components/*": ["src/components/*"], - "@layouts/*": ["src/layouts/*"], - "@token/*": ["src/token/*"], - "@theme/*": ["src/theme/*"], - "@assets/*": ["src/assets/*"] - }, - "jsxImportSource": "@emotion/react", - "allowSyntheticDefaultImports": true - }, - "include": ["src"], - "exclude": ["./node_modules", "dist"] -} diff --git a/client/.gitignore b/client/.gitignore deleted file mode 100644 index afd0485d1..000000000 --- a/client/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -logs -*.log -npm-debug.log* - -node_modules -dist - -.env - -*storybook.log -.DS_Store diff --git a/client/.npmrc b/client/.npmrc deleted file mode 100644 index ece05f588..000000000 --- a/client/.npmrc +++ /dev/null @@ -1,2 +0,0 @@ -engine-strict = true -legacy-peer-deps = true diff --git a/client/.prettierrc b/client/.prettierrc deleted file mode 100644 index 94ad823ef..000000000 --- a/client/.prettierrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "singleQuote": true, - "trailingComma": "all", - "printWidth": 120, - "tabWidth": 2, - "semi": true, - "arrowParens": "avoid", - "endOfLine": "auto", - "jsxSingleQuote": false, - "bracketSpacing": false, - "proseWrap": "preserve" -} \ No newline at end of file diff --git a/client/eslint.config.mjs b/client/eslint.config.mjs deleted file mode 100644 index 106f6ccde..000000000 --- a/client/eslint.config.mjs +++ /dev/null @@ -1,107 +0,0 @@ -import {dirname} from 'path'; -import {fileURLToPath} from 'url'; -import reactPlugin from 'eslint-plugin-react'; -import tsPlugin from '@typescript-eslint/eslint-plugin'; -import importPlugin from 'eslint-plugin-import'; -import prettierPlugin from 'eslint-plugin-prettier'; -import typescriptParser from '@typescript-eslint/parser'; - -const __dirname = dirname(fileURLToPath(import.meta.url)); - -export default [ - { - files: ['src/**/*.{js,jsx,ts,tsx}'], - languageOptions: { - ecmaVersion: 2021, - sourceType: 'module', - parser: typescriptParser, - parserOptions: { - ecmaFeatures: { - jsx: true, - }, - }, - }, - plugins: { - react: reactPlugin, - '@typescript-eslint': tsPlugin, - import: importPlugin, - prettier: prettierPlugin, - }, - rules: { - 'prettier/prettier': 'error', - 'react/react-in-jsx-scope': 'off', - 'react/prop-types': 'off', - 'react/jsx-uses-vars': 'error', - // '@typescript-eslint/no-use-before-define': ['error'], - // '@typescript-eslint/explicit-module-boundary-types': 'error', - // "import/no-unresolved": "error", - 'import/order': [ - 'error', - { - 'newlines-between': 'always', - groups: ['type', 'builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'unknown'], - pathGroups: [ - { - pattern: 'react*', - group: 'external', - position: 'before', - }, - { - pattern: '@hooks/*', - group: 'internal', - position: 'after', - }, - { - pattern: '@apis/*', - group: 'internal', - position: 'after', - }, - { - pattern: '@pages/*', - group: 'internal', - position: 'after', - }, - { - pattern: '@components/*', - group: 'internal', - position: 'after', - }, - { - pattern: '@assets/*', - group: 'internal', - position: 'after', - }, - { - pattern: '@utils/*', - group: 'internal', - position: 'after', - }, - { - pattern: '@constants/*', - group: 'internal', - position: 'after', - }, - { - pattern: '@mocks/*', - group: 'internal', - position: 'after', - }, - ], - }, - ], - }, - settings: { - 'import/resolver': { - node: { - extensions: ['.js', '.jsx', '.ts', '.tsx'], - }, - typescript: { - directory: './src', - }, - }, - 'import/parsers': { - '@typescript-eslint/parser': ['.ts', '.tsx'], - }, - }, - }, -]; diff --git a/client/index.html b/client/index.html deleted file mode 100644 index 97edcf3ca..000000000 --- a/client/index.html +++ /dev/null @@ -1,12 +0,0 @@ -<!doctype html> -<html lang="ko"> - <head> - <meta charset="UTF-8" /> - <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=0" /> - <meta content="upgrade-insecure-requests" /> - <title>행동대장 - - -
- - diff --git a/client/package-lock.json b/client/package-lock.json deleted file mode 100644 index 91269318a..000000000 --- a/client/package-lock.json +++ /dev/null @@ -1,11135 +0,0 @@ -{ - "name": "haengdong-client", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "haengdong-client", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "@emotion/react": "^11.11.4", - "@types/dotenv-webpack": "^7.0.7", - "dotenv-webpack": "^8.1.0", - "haengdong-design": "^0.1.35", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "react-router-dom": "^6.24.1" - }, - "devDependencies": { - "@eslint/compat": "^1.1.0", - "@eslint/js": "^9.6.0", - "@svgr/webpack": "^8.1.0", - "@types/react": "^18.3.3", - "@types/react-dom": "^18.3.0", - "@typescript-eslint/eslint-plugin": "^7.16.0", - "@typescript-eslint/parser": "^7.16.0", - "css-loader": "^7.1.2", - "dotenv": "^16.4.5", - "eslint": "^9.6.0", - "eslint-import-resolver-typescript": "^3.6.1", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jsx-a11y": "^6.9.0", - "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-react": "^7.34.3", - "eslint-plugin-react-hooks": "^4.6.2", - "fork-ts-checker-webpack-plugin": "^9.0.2", - "globals": "^15.8.0", - "html-loader": "^5.0.0", - "html-webpack-plugin": "^5.6.0", - "modify-source-webpack-plugin": "^4.1.0", - "prettier": "3.3.2", - "style-loader": "^4.0.0", - "ts-loader": "^9.5.1", - "typescript": "^5.5.3", - "typescript-eslint": "^7.16.0", - "webpack": "^5.93.0", - "webpack-cli": "^5.1.4", - "webpack-dev-server": "^5.0.4" - }, - "engines": { - "node": ">=20.15.1", - "npm": ">=10.7.0" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", - "dependencies": { - "@babel/highlight": "^7.24.7", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.9.tgz", - "integrity": "sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz", - "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.9", - "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-module-transforms": "^7.24.9", - "@babel/helpers": "^7.24.8", - "@babel/parser": "^7.24.8", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.8", - "@babel/types": "^7.24.9", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" - }, - "node_modules/@babel/generator": { - "version": "7.24.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.10.tgz", - "integrity": "sha512-o9HBZL1G2129luEUlG1hB4N/nlYNWHnpwlND9eOMclRqqu1YDy2sSYVCFUZwl8I1Gxh+QSRrP2vD7EpUmFVXxg==", - "dependencies": { - "@babel/types": "^7.24.9", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", - "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", - "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz", - "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==", - "dependencies": { - "@babel/compat-data": "^7.24.8", - "@babel/helper-validator-option": "^7.24.8", - "browserslist": "^4.23.1", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.8.tgz", - "integrity": "sha512-4f6Oqnmyp2PP3olgUMmOwC3akxSm5aBYraQ6YDdKy7NcAMkDECHWG0DEnV6M2UAkERgIBhYt8S27rURPg7SxWA==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-member-expression-to-functions": "^7.24.8", - "@babel/helper-optimise-call-expression": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.7.tgz", - "integrity": "sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "regexpu-core": "^5.3.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", - "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", - "dependencies": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", - "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", - "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", - "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", - "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", - "dependencies": { - "@babel/traverse": "^7.24.8", - "@babel/types": "^7.24.8" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz", - "integrity": "sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==", - "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", - "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", - "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.7.tgz", - "integrity": "sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-wrap-function": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz", - "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==", - "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-member-expression-to-functions": "^7.24.7", - "@babel/helper-optimise-call-expression": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", - "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", - "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", - "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", - "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.7.tgz", - "integrity": "sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==", - "dependencies": { - "@babel/helper-function-name": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz", - "integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==", - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.8" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", - "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.7.tgz", - "integrity": "sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==", - "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.7.tgz", - "integrity": "sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", - "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.7.tgz", - "integrity": "sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==", - "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", - "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", - "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", - "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", - "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-unicode-sets-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", - "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", - "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.7.tgz", - "integrity": "sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==", - "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-remap-async-to-generator": "^7.24.7", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", - "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", - "dependencies": { - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-remap-async-to-generator": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", - "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.7.tgz", - "integrity": "sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz", - "integrity": "sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", - "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.8.tgz", - "integrity": "sha512-VXy91c47uujj758ud9wx+OMgheXm4qJfyhj1P18YvlrQkNOSrwsteHk+EFS3OMGfhMhpZa0A+81eE7G4QC+3CA==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-replace-supers": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-classes/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", - "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/template": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", - "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", - "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", - "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", - "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", - "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", - "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", - "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", - "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.7.tgz", - "integrity": "sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==", - "dependencies": { - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", - "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.7.tgz", - "integrity": "sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", - "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", - "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", - "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", - "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", - "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", - "dependencies": { - "@babel/helper-module-transforms": "^7.24.8", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-simple-access": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.7.tgz", - "integrity": "sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==", - "dependencies": { - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", - "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", - "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", - "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", - "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", - "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", - "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", - "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", - "dependencies": { - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", - "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", - "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", - "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", - "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz", - "integrity": "sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", - "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", - "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-constant-elements": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.24.7.tgz", - "integrity": "sha512-7LidzZfUXyfZ8/buRW6qIIHBY8wAZ1OrY9c/wTr8YhZ6vMPo+Uc/CVFLYY1spZrEQlD4w5u8wjqk5NQ3OVqQKA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.7.tgz", - "integrity": "sha512-H/Snz9PFxKsS1JLI4dJLtnJgCJRoo0AUm3chP6NYr+9En1JMKloheEiLIhlp5MDVznWo+H3AAC1Mc8lmUEpsgg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.24.7.tgz", - "integrity": "sha512-+Dj06GDZEFRYvclU6k4bme55GKBEWUmByM/eoKuqg4zTNQHiApWRhQph5fxQB2wAEFvRzL1tOEj1RJ19wJrhoA==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-jsx": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.24.7.tgz", - "integrity": "sha512-QG9EnzoGn+Qar7rxuW+ZOsbWOt56FvvI93xInqsZDC5fsekx1AlIO4KIJ5M+D0p0SqSH156EpmZyXq630B8OlQ==", - "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.7.tgz", - "integrity": "sha512-PLgBVk3fzbmEjBJ/u8kFzOqS9tUeDjiaWud/rRym/yjCo/M9cASPlnrd2ZmmZpQT40fOOrvR8jh+n8jikrOhNA==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", - "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "regenerator-transform": "^0.15.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", - "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", - "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", - "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", - "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", - "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", - "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typescript": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.8.tgz", - "integrity": "sha512-CgFgtN61BbdOGCP4fLaAMOPkzWUh6yQZNMr5YSt8uz2cZSSiQONCQFWqsE4NeVfOIhqDOlS9CR3WD91FzMeB2Q==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-create-class-features-plugin": "^7.24.8", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/plugin-syntax-typescript": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", - "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", - "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", - "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz", - "integrity": "sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.8.tgz", - "integrity": "sha512-vObvMZB6hNWuDxhSaEPTKCwcqkAIuDtE+bQGn4XMXne1DSLzFVY8Vmj1bm+mUQXYNN8NmaQEO+r8MMbzPr1jBQ==", - "dependencies": { - "@babel/compat-data": "^7.24.8", - "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-validator-option": "^7.24.8", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.7", - "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.24.7", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.24.7", - "@babel/plugin-transform-async-generator-functions": "^7.24.7", - "@babel/plugin-transform-async-to-generator": "^7.24.7", - "@babel/plugin-transform-block-scoped-functions": "^7.24.7", - "@babel/plugin-transform-block-scoping": "^7.24.7", - "@babel/plugin-transform-class-properties": "^7.24.7", - "@babel/plugin-transform-class-static-block": "^7.24.7", - "@babel/plugin-transform-classes": "^7.24.8", - "@babel/plugin-transform-computed-properties": "^7.24.7", - "@babel/plugin-transform-destructuring": "^7.24.8", - "@babel/plugin-transform-dotall-regex": "^7.24.7", - "@babel/plugin-transform-duplicate-keys": "^7.24.7", - "@babel/plugin-transform-dynamic-import": "^7.24.7", - "@babel/plugin-transform-exponentiation-operator": "^7.24.7", - "@babel/plugin-transform-export-namespace-from": "^7.24.7", - "@babel/plugin-transform-for-of": "^7.24.7", - "@babel/plugin-transform-function-name": "^7.24.7", - "@babel/plugin-transform-json-strings": "^7.24.7", - "@babel/plugin-transform-literals": "^7.24.7", - "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", - "@babel/plugin-transform-member-expression-literals": "^7.24.7", - "@babel/plugin-transform-modules-amd": "^7.24.7", - "@babel/plugin-transform-modules-commonjs": "^7.24.8", - "@babel/plugin-transform-modules-systemjs": "^7.24.7", - "@babel/plugin-transform-modules-umd": "^7.24.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", - "@babel/plugin-transform-new-target": "^7.24.7", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", - "@babel/plugin-transform-numeric-separator": "^7.24.7", - "@babel/plugin-transform-object-rest-spread": "^7.24.7", - "@babel/plugin-transform-object-super": "^7.24.7", - "@babel/plugin-transform-optional-catch-binding": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.8", - "@babel/plugin-transform-parameters": "^7.24.7", - "@babel/plugin-transform-private-methods": "^7.24.7", - "@babel/plugin-transform-private-property-in-object": "^7.24.7", - "@babel/plugin-transform-property-literals": "^7.24.7", - "@babel/plugin-transform-regenerator": "^7.24.7", - "@babel/plugin-transform-reserved-words": "^7.24.7", - "@babel/plugin-transform-shorthand-properties": "^7.24.7", - "@babel/plugin-transform-spread": "^7.24.7", - "@babel/plugin-transform-sticky-regex": "^7.24.7", - "@babel/plugin-transform-template-literals": "^7.24.7", - "@babel/plugin-transform-typeof-symbol": "^7.24.8", - "@babel/plugin-transform-unicode-escapes": "^7.24.7", - "@babel/plugin-transform-unicode-property-regex": "^7.24.7", - "@babel/plugin-transform-unicode-regex": "^7.24.7", - "@babel/plugin-transform-unicode-sets-regex": "^7.24.7", - "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.10.4", - "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.37.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.6-no-external-plugins", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", - "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@babel/preset-react": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.24.7.tgz", - "integrity": "sha512-AAH4lEkpmzFWrGVlHaxJB7RLH21uPQ9+He+eFLWHmF9IuFQVugz8eAsamaW0DXRrTfco5zj1wWtpdcXJUOfsag==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "@babel/plugin-transform-react-display-name": "^7.24.7", - "@babel/plugin-transform-react-jsx": "^7.24.7", - "@babel/plugin-transform-react-jsx-development": "^7.24.7", - "@babel/plugin-transform-react-pure-annotations": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-typescript": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.7.tgz", - "integrity": "sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "@babel/plugin-syntax-jsx": "^7.24.7", - "@babel/plugin-transform-modules-commonjs": "^7.24.7", - "@babel/plugin-transform-typescript": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" - }, - "node_modules/@babel/runtime": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", - "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", - "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz", - "integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==", - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.8", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/parser": "^7.24.8", - "@babel/types": "^7.24.8", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.9.tgz", - "integrity": "sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==", - "dependencies": { - "@babel/helper-string-parser": "^7.24.8", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", - "dev": true, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@emotion/babel-plugin": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz", - "integrity": "sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==", - "dependencies": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/runtime": "^7.18.3", - "@emotion/hash": "^0.9.2", - "@emotion/memoize": "^0.9.0", - "@emotion/serialize": "^1.2.0", - "babel-plugin-macros": "^3.1.0", - "convert-source-map": "^1.5.0", - "escape-string-regexp": "^4.0.0", - "find-root": "^1.1.0", - "source-map": "^0.5.7", - "stylis": "4.2.0" - } - }, - "node_modules/@emotion/cache": { - "version": "11.13.0", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.0.tgz", - "integrity": "sha512-hPV345J/tH0Cwk2wnU/3PBzORQ9HeX+kQSbwI+jslzpRCHE6fSGTohswksA/Ensr8znPzwfzKZCmAM9Lmlhp7g==", - "dependencies": { - "@emotion/memoize": "^0.9.0", - "@emotion/sheet": "^1.4.0", - "@emotion/utils": "^1.4.0", - "@emotion/weak-memoize": "^0.4.0", - "stylis": "4.2.0" - } - }, - "node_modules/@emotion/hash": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", - "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==" - }, - "node_modules/@emotion/memoize": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", - "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" - }, - "node_modules/@emotion/react": { - "version": "11.13.0", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.0.tgz", - "integrity": "sha512-WkL+bw1REC2VNV1goQyfxjx1GYJkcc23CRQkXX+vZNLINyfI7o+uUn/rTGPt/xJ3bJHd5GcljgnxHf4wRw5VWQ==", - "dependencies": { - "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.12.0", - "@emotion/cache": "^11.13.0", - "@emotion/serialize": "^1.3.0", - "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", - "@emotion/utils": "^1.4.0", - "@emotion/weak-memoize": "^0.4.0", - "hoist-non-react-statics": "^3.3.1" - }, - "peerDependencies": { - "react": ">=16.8.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@emotion/serialize": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.0.tgz", - "integrity": "sha512-jACuBa9SlYajnpIVXB+XOXnfJHyckDfe6fOpORIM6yhBDlqGuExvDdZYHDQGoDf3bZXGv7tNr+LpLjJqiEQ6EA==", - "dependencies": { - "@emotion/hash": "^0.9.2", - "@emotion/memoize": "^0.9.0", - "@emotion/unitless": "^0.9.0", - "@emotion/utils": "^1.4.0", - "csstype": "^3.0.2" - } - }, - "node_modules/@emotion/sheet": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", - "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==" - }, - "node_modules/@emotion/unitless": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.9.0.tgz", - "integrity": "sha512-TP6GgNZtmtFaFcsOgExdnfxLLpRDla4Q66tnenA9CktvVSdNKDvMVuUah4QvWPIpNjrWsGg3qeGo9a43QooGZQ==" - }, - "node_modules/@emotion/use-insertion-effect-with-fallbacks": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz", - "integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==", - "peerDependencies": { - "react": ">=16.8.0" - } - }, - "node_modules/@emotion/utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.0.tgz", - "integrity": "sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ==" - }, - "node_modules/@emotion/weak-memoize": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", - "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", - "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/compat": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.1.1.tgz", - "integrity": "sha512-lpHyRyplhGPL5mGEh6M9O5nnKk0Gz4bFI+Zu6tKlPpDUN7XshWvH9C/px4UVm87IAANE0W81CEsNGbS1KlzXpA==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", - "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", - "dev": true, - "dependencies": { - "@eslint/object-schema": "^2.1.4", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/js": { - "version": "9.7.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.7.0.tgz", - "integrity": "sha512-ChuWDQenef8OSFnvuxv0TCVxEwmu3+hPNKvM9B34qpM0rDRbjL8t5QkQeHHeAfsKQjuH9wS82WeCi1J/owatng==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", - "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", - "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", - "dev": true, - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@jsonjoy.com/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", - "dev": true, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/json-pack": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.0.4.tgz", - "integrity": "sha512-aOcSN4MeAtFROysrbqG137b7gaDDSmVrl5mpo6sT/w+kcXpWnzhMjmY/Fh/sDx26NBxyIE7MB1seqLeCAzy9Sg==", - "dev": true, - "dependencies": { - "@jsonjoy.com/base64": "^1.1.1", - "@jsonjoy.com/util": "^1.1.2", - "hyperdyperid": "^1.2.0", - "thingies": "^1.20.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/util": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.2.0.tgz", - "integrity": "sha512-4B8B+3vFsY4eo33DMKyJPlQ3sBMpPFUZK2dr3O3rXrOGKKbYG44J0XSFkDo1VOQiri5HFEhIeVvItjR2xcazmg==", - "dev": true, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", - "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", - "dev": true - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/@remix-run/router": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.18.0.tgz", - "integrity": "sha512-L3jkqmqoSVBVKHfpGZmLrex0lxR5SucGA0sUfFzGctehw+S/ggL9L/0NnC5mw6P8HUWpFZ3nQw3cRApjjWx9Sw==", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@svgr/babel-plugin-add-jsx-attribute": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", - "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", - "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", - "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", - "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-svg-dynamic-title": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", - "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-svg-em-dimensions": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", - "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-transform-react-native-svg": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", - "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-transform-svg-component": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", - "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", - "engines": { - "node": ">=12" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-preset": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", - "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", - "dependencies": { - "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", - "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", - "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", - "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", - "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", - "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", - "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", - "@svgr/babel-plugin-transform-svg-component": "8.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/core": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", - "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", - "dependencies": { - "@babel/core": "^7.21.3", - "@svgr/babel-preset": "8.1.0", - "camelcase": "^6.2.0", - "cosmiconfig": "^8.1.3", - "snake-case": "^3.0.4" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/hast-util-to-babel-ast": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", - "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", - "dependencies": { - "@babel/types": "^7.21.3", - "entities": "^4.4.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/plugin-jsx": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", - "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", - "dependencies": { - "@babel/core": "^7.21.3", - "@svgr/babel-preset": "8.1.0", - "@svgr/hast-util-to-babel-ast": "8.0.0", - "svg-parser": "^2.0.4" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@svgr/core": "*" - } - }, - "node_modules/@svgr/plugin-svgo": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", - "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", - "dependencies": { - "cosmiconfig": "^8.1.3", - "deepmerge": "^4.3.1", - "svgo": "^3.0.2" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@svgr/core": "*" - } - }, - "node_modules/@svgr/webpack": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", - "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", - "dependencies": { - "@babel/core": "^7.21.3", - "@babel/plugin-transform-react-constant-elements": "^7.21.3", - "@babel/preset-env": "^7.20.2", - "@babel/preset-react": "^7.18.6", - "@babel/preset-typescript": "^7.21.0", - "@svgr/core": "8.1.0", - "@svgr/plugin-jsx": "8.1.0", - "@svgr/plugin-svgo": "8.1.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@trysound/sax": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", - "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", - "dev": true, - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/bonjour": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", - "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect-history-api-fallback": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", - "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", - "dev": true, - "dependencies": { - "@types/express-serve-static-core": "*", - "@types/node": "*" - } - }, - "node_modules/@types/dotenv-webpack": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/dotenv-webpack/-/dotenv-webpack-7.0.7.tgz", - "integrity": "sha512-tltVokFUeYuSjNmHc6N892Asu/JIQcnH2iUF5A29/VKqv9opq6KlrmnKd/Lt/bBikV/z0YN2K0kguTwWirYCMQ==", - "dependencies": { - "@types/node": "*", - "tapable": "^2.2.0", - "webpack": "^5" - } - }, - "node_modules/@types/eslint": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.0.tgz", - "integrity": "sha512-gi6WQJ7cHRgZxtkQEoyHMppPjq9Kxo5Tjn2prSKDSmZrCz8TZ3jSRCeTJm+WoM+oB0WG37bRqLzaaU3q7JypGg==", - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" - }, - "node_modules/@types/express": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", - "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", - "dev": true, - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.19.5", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", - "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", - "dev": true - }, - "node_modules/@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true - }, - "node_modules/@types/http-proxy": { - "version": "1.17.14", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", - "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true - }, - "node_modules/@types/node": { - "version": "20.14.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz", - "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/node-forge": { - "version": "1.3.11", - "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", - "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/parse-json": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" - }, - "node_modules/@types/prop-types": { - "version": "15.7.12", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "dev": true - }, - "node_modules/@types/qs": { - "version": "6.9.15", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", - "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", - "dev": true - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true - }, - "node_modules/@types/react": { - "version": "18.3.3", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", - "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", - "dev": true, - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", - "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", - "dev": true, - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/retry": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", - "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", - "dev": true - }, - "node_modules/@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", - "dev": true, - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/serve-index": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", - "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", - "dev": true, - "dependencies": { - "@types/express": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.7", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", - "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", - "dev": true, - "dependencies": { - "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "*" - } - }, - "node_modules/@types/sockjs": { - "version": "0.3.36", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", - "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/ws": { - "version": "8.5.11", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.11.tgz", - "integrity": "sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.17.0.tgz", - "integrity": "sha512-pyiDhEuLM3PuANxH7uNYan1AaFs5XE0zw1hq69JBvGvE7gSuEoQl1ydtEe/XQeoC3GQxLXyOVa5kNOATgM638A==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.17.0", - "@typescript-eslint/type-utils": "7.17.0", - "@typescript-eslint/utils": "7.17.0", - "@typescript-eslint/visitor-keys": "7.17.0", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.17.0.tgz", - "integrity": "sha512-puiYfGeg5Ydop8eusb/Hy1k7QmOU6X3nvsqCgzrB2K4qMavK//21+PzNE8qeECgNOIoertJPUC1SpegHDI515A==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "7.17.0", - "@typescript-eslint/types": "7.17.0", - "@typescript-eslint/typescript-estree": "7.17.0", - "@typescript-eslint/visitor-keys": "7.17.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.17.0.tgz", - "integrity": "sha512-0P2jTTqyxWp9HiKLu/Vemr2Rg1Xb5B7uHItdVZ6iAenXmPo4SZ86yOPCJwMqpCyaMiEHTNqizHfsbmCFT1x9SA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.17.0", - "@typescript-eslint/visitor-keys": "7.17.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.17.0.tgz", - "integrity": "sha512-XD3aaBt+orgkM/7Cei0XNEm1vwUxQ958AOLALzPlbPqb8C1G8PZK85tND7Jpe69Wualri81PLU+Zc48GVKIMMA==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "7.17.0", - "@typescript-eslint/utils": "7.17.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.17.0.tgz", - "integrity": "sha512-a29Ir0EbyKTKHnZWbNsrc/gqfIBqYPwj3F2M+jWE/9bqfEHg0AMtXzkbUkOG6QgEScxh2+Pz9OXe11jHDnHR7A==", - "dev": true, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.17.0.tgz", - "integrity": "sha512-72I3TGq93t2GoSBWI093wmKo0n6/b7O4j9o8U+f65TVD0FS6bI2180X5eGEr8MA8PhKMvYe9myZJquUT2JkCZw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.17.0", - "@typescript-eslint/visitor-keys": "7.17.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.17.0.tgz", - "integrity": "sha512-r+JFlm5NdB+JXc7aWWZ3fKSm1gn0pkswEwIYsrGPdsT2GjsRATAKXiNtp3vgAAO1xZhX8alIOEQnNMl3kbTgJw==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.17.0", - "@typescript-eslint/types": "7.17.0", - "@typescript-eslint/typescript-estree": "7.17.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.17.0.tgz", - "integrity": "sha512-RVGC9UhPOCsfCdI9pU++K4nD7to+jTcMIbXTSOcrLqUEW6gF2pU1UUbYJKc9cvcRSK1UDeMJ7pdMxf4bhMpV/A==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.17.0", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", - "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", - "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", - "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==" - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", - "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.12.1" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", - "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-opt": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1", - "@webassemblyjs/wast-printer": "1.12.1" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", - "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", - "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", - "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", - "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webpack-cli/configtest": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", - "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", - "dev": true, - "engines": { - "node": ">=14.15.0" - }, - "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" - } - }, - "node_modules/@webpack-cli/info": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", - "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", - "dev": true, - "engines": { - "node": ">=14.15.0" - }, - "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" - } - }, - "node_modules/@webpack-cli/serve": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", - "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", - "dev": true, - "engines": { - "node": ">=14.15.0" - }, - "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" - }, - "peerDependenciesMeta": { - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-import-attributes": { - "version": "1.9.5", - "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", - "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", - "peerDependencies": { - "acorn": "^8" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", - "dev": true, - "engines": [ - "node >= 0.8.0" - ], - "bin": { - "ansi-html": "bin/ansi-html" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "dev": true, - "dependencies": { - "deep-equal": "^2.0.5" - } - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true - }, - "node_modules/array-includes": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", - "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array.prototype.findlast": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", - "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", - "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.tosorted": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", - "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", - "es-errors": "^1.3.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/ast-types-flow": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", - "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", - "dev": true - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dev": true, - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/axe-core": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.9.1.tgz", - "integrity": "sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/axobject-query": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", - "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", - "dev": true, - "dependencies": { - "deep-equal": "^2.0.5" - } - }, - "node_modules/babel-plugin-macros": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", - "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", - "dependencies": { - "@babel/runtime": "^7.12.5", - "cosmiconfig": "^7.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">=10", - "npm": ">=6" - } - }, - "node_modules/babel-plugin-macros/node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.11", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", - "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", - "dependencies": { - "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.6.2", - "semver": "^6.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz", - "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.1", - "core-js-compat": "^3.36.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", - "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true - }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", - "dev": true, - "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.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/bonjour-service": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", - "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "multicast-dns": "^7.2.5" - } - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" - }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.23.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", - "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001640", - "electron-to-chromium": "^1.4.820", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.1.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "node_modules/bundle-name": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", - "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", - "dev": true, - "dependencies": { - "run-applescript": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", - "dev": true, - "dependencies": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001643", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001643.tgz", - "integrity": "sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/chrome-trace-event": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", - "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", - "engines": { - "node": ">=6.0" - } - }, - "node_modules/clean-css": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", - "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", - "dev": true, - "dependencies": { - "source-map": "~0.6.0" - }, - "engines": { - "node": ">= 10.0" - } - }, - "node_modules/clean-css/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true - }, - "node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "dev": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "dev": true, - "dependencies": { - "mime-db": ">= 1.43.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", - "dev": true, - "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/compression/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/connect-history-api-fallback": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", - "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" - }, - "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true - }, - "node_modules/core-js-compat": { - "version": "3.37.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", - "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", - "dependencies": { - "browserslist": "^4.23.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dependencies": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css-loader": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.2.tgz", - "integrity": "sha512-6WvYYn7l/XEGN8Xu2vWFt9nVzrCn39vKyTEFf/ExEyoksJjjSZV/0/35XPlMbpnr6VGhZIUg5yJrL8tGfes/FA==", - "dev": true, - "dependencies": { - "icss-utils": "^5.1.0", - "postcss": "^8.4.33", - "postcss-modules-extract-imports": "^3.1.0", - "postcss-modules-local-by-default": "^4.0.5", - "postcss-modules-scope": "^3.2.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "@rspack/core": "0.x || 1.x", - "webpack": "^5.27.0" - }, - "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - }, - "webpack": { - "optional": true - } - } - }, - "node_modules/css-loader/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/css-select": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dependencies": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" - } - }, - "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/csso": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", - "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", - "dependencies": { - "css-tree": "~2.2.0" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/csso/node_modules/css-tree": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", - "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", - "dependencies": { - "mdn-data": "2.0.28", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/csso/node_modules/mdn-data": { - "version": "2.0.28", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", - "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==" - }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" - }, - "node_modules/damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", - "dev": true - }, - "node_modules/data-view-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", - "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", - "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", - "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-equal": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", - "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.5", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.2", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.2", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-browser": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", - "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", - "dev": true, - "dependencies": { - "bundle-name": "^4.1.0", - "default-browser-id": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser-id": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", - "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-gateway": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", - "dev": true, - "dependencies": { - "execa": "^5.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-lazy-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", - "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dns-packet": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", - "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", - "dev": true, - "dependencies": { - "@leichtgewicht/ip-codec": "^2.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", - "dev": true, - "dependencies": { - "utila": "~0.4" - } - }, - "node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "dev": true, - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/dom-serializer/node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "dev": true, - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/dotenv-defaults": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dotenv-defaults/-/dotenv-defaults-2.0.2.tgz", - "integrity": "sha512-iOIzovWfsUHU91L5i8bJce3NYK5JXeAwH50Jh6+ARUdLiiGlYWfGw6UkzsYqaXZH/hjE/eCd/PlfM/qqyK0AMg==", - "dependencies": { - "dotenv": "^8.2.0" - } - }, - "node_modules/dotenv-defaults/node_modules/dotenv": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", - "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", - "engines": { - "node": ">=10" - } - }, - "node_modules/dotenv-webpack": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/dotenv-webpack/-/dotenv-webpack-8.1.0.tgz", - "integrity": "sha512-owK1JcsPkIobeqjVrk6h7jPED/W6ZpdFsMPR+5ursB7/SdgDyO+VzAU+szK8C8u3qUhtENyYnj8eyXMR5kkGag==", - "dependencies": { - "dotenv-defaults": "^2.0.2" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "webpack": "^4 || ^5" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true - }, - "node_modules/electron-to-chromium": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.0.tgz", - "integrity": "sha512-Vb3xHHYnLseK8vlMJQKJYXJ++t4u1/qJ3vykuVrVjvdiOEhYyT1AuP4x03G8EnPmYvYOhe9T+dADTmthjRQMkA==" - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", - "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/envinfo": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", - "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", - "dev": true, - "bin": { - "envinfo": "dist/cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.23.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", - "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "data-view-buffer": "^1.0.1", - "data-view-byte-length": "^1.0.1", - "data-view-byte-offset": "^1.0.0", - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-set-tostringtag": "^2.0.3", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "hasown": "^2.0.2", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.1", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.2", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.9", - "string.prototype.trimend": "^1.0.8", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.6", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.15" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-iterator-helpers": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", - "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", - "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.3", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.7", - "iterator.prototype": "^1.1.2", - "safe-array-concat": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-module-lexer": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", - "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==" - }, - "node_modules/es-object-atoms": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", - "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "9.7.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.7.0.tgz", - "integrity": "sha512-FzJ9D/0nGiCGBf8UXO/IGLTgLVzIxze1zpfA8Ton2mjLovXdAPlYDv+MQDcqj3TmrhAGYfOpz9RfR+ent0AgAw==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.11.0", - "@eslint/config-array": "^0.17.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.7.0", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.3.0", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.0.2", - "eslint-visitor-keys": "^4.0.0", - "espree": "^10.1.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "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" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-import-resolver-typescript": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", - "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", - "dev": true, - "dependencies": { - "debug": "^4.3.4", - "enhanced-resolve": "^5.12.0", - "eslint-module-utils": "^2.7.4", - "fast-glob": "^3.3.1", - "get-tsconfig": "^4.5.0", - "is-core-module": "^2.11.0", - "is-glob": "^4.0.3" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" - }, - "peerDependencies": { - "eslint": "*", - "eslint-plugin-import": "*" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", - "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", - "dev": true, - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", - "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", - "object.values": "^1.1.7", - "semver": "^6.3.1", - "tsconfig-paths": "^3.15.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.9.0.tgz", - "integrity": "sha512-nOFOCaJG2pYqORjK19lqPqxMO/JpvdCZdPtNdxY3kvom3jTvkAbOvQvD8wuD0G8BYR0IGAGYDlzqWJOh/ybn2g==", - "dev": true, - "dependencies": { - "aria-query": "~5.1.3", - "array-includes": "^3.1.8", - "array.prototype.flatmap": "^1.3.2", - "ast-types-flow": "^0.0.8", - "axe-core": "^4.9.1", - "axobject-query": "~3.1.1", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "es-iterator-helpers": "^1.0.19", - "hasown": "^2.0.2", - "jsx-ast-utils": "^3.3.5", - "language-tags": "^1.0.9", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "safe-regex-test": "^1.0.3", - "string.prototype.includes": "^2.0.0" - }, - "engines": { - "node": ">=4.0" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", - "integrity": "sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==", - "dev": true, - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.9.1" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "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 - } - } - }, - "node_modules/eslint-plugin-react": { - "version": "7.35.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.35.0.tgz", - "integrity": "sha512-v501SSMOWv8gerHkk+IIQBkcGRGrO2nfybfj5pLxuJNFTPxxA3PSryhXTK+9pNbtkggheDdsC0E9Q8CuPk6JKA==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.8", - "array.prototype.findlast": "^1.2.5", - "array.prototype.flatmap": "^1.3.2", - "array.prototype.tosorted": "^1.1.4", - "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.19", - "estraverse": "^5.3.0", - "hasown": "^2.0.2", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.8", - "object.fromentries": "^2.0.8", - "object.values": "^1.2.0", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.5", - "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.11", - "string.prototype.repeat": "^1.0.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", - "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/eslint-plugin-react/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-react/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/eslint-scope": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", - "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/eslint/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", - "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/espree": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", - "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", - "dev": true, - "dependencies": { - "acorn": "^8.12.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", - "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", - "dev": true, - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.2", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.6.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" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fast-uri": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", - "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", - "dev": true - }, - "node_modules/fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "dev": true, - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "dev": true, - "dependencies": { - "websocket-driver": ">=0.5.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dev": true, - "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" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/foreground-child": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", - "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/fork-ts-checker-webpack-plugin": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-9.0.2.tgz", - "integrity": "sha512-Uochze2R8peoN1XqlSi/rGUkDQpRogtLFocP9+PGu68zk1BDAKXfdeCdyVZpgTk8V8WFVQXdEz426VKjXLO1Gg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.7", - "chalk": "^4.1.2", - "chokidar": "^3.5.3", - "cosmiconfig": "^8.2.0", - "deepmerge": "^4.2.2", - "fs-extra": "^10.0.0", - "memfs": "^3.4.1", - "minimatch": "^3.0.4", - "node-abort-controller": "^3.0.1", - "schema-utils": "^3.1.1", - "semver": "^7.3.5", - "tapable": "^2.2.1" - }, - "engines": { - "node": ">=12.13.0", - "yarn": ">=1.0.0" - }, - "peerDependencies": { - "typescript": ">3.6.0", - "webpack": "^5.11.0" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/fs-monkey": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", - "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-tsconfig": { - "version": "4.7.6", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.6.tgz", - "integrity": "sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==", - "dev": true, - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" - }, - "node_modules/globals": { - "version": "15.8.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.8.0.tgz", - "integrity": "sha512-VZAJ4cewHTExBWDHR6yptdIBlx9YSSZuwojj9Nt5mBRXQzrKakDsVKQ1J63sklLvzAJm0X5+RpO4i3Y2hcOnFw==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/haengdong-design": { - "version": "0.1.35", - "resolved": "https://registry.npmjs.org/haengdong-design/-/haengdong-design-0.1.35.tgz", - "integrity": "sha512-JhlZgZXzYfCMV57glEOiI+YKGstGAAOhBOKGad6Mugio/vNVUmInf3/eJPEy/10SM9reizYsSCt7eoyj71ZaSA==", - "dependencies": { - "@emotion/react": "^11.11.4", - "@svgr/webpack": "^8.1.0", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "react-router-dom": "^6.24.1" - }, - "engines": { - "node": ">=20.15.1", - "npm": ">=10.7.0" - } - }, - "node_modules/handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "dependencies": { - "react-is": "^16.7.0" - } - }, - "node_modules/hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "node_modules/hpack.js/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "node_modules/hpack.js/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/hpack.js/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/hpack.js/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/html-entities": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", - "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/mdevils" - }, - { - "type": "patreon", - "url": "https://patreon.com/mdevils" - } - ] - }, - "node_modules/html-loader": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-5.0.0.tgz", - "integrity": "sha512-puaGKdjdVVIFRtgIC2n5dt5bt0N5j6heXlAQZ4Do1MLjHmOT1gCE1Ogg7XZNeJlnOVHHsrZKGs5dfh+XwZ3XPw==", - "dev": true, - "dependencies": { - "html-minifier-terser": "^7.2.0", - "parse5": "^7.1.2" - }, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/html-minifier-terser": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", - "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", - "dev": true, - "dependencies": { - "camel-case": "^4.1.2", - "clean-css": "~5.3.2", - "commander": "^10.0.0", - "entities": "^4.4.0", - "param-case": "^3.0.4", - "relateurl": "^0.2.7", - "terser": "^5.15.1" - }, - "bin": { - "html-minifier-terser": "cli.js" - }, - "engines": { - "node": "^14.13.1 || >=16.0.0" - } - }, - "node_modules/html-webpack-plugin": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", - "integrity": "sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==", - "dev": true, - "dependencies": { - "@types/html-minifier-terser": "^6.0.0", - "html-minifier-terser": "^6.0.2", - "lodash": "^4.17.21", - "pretty-error": "^4.0.0", - "tapable": "^2.0.0" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/html-webpack-plugin" - }, - "peerDependencies": { - "@rspack/core": "0.x || 1.x", - "webpack": "^5.20.0" - }, - "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - }, - "webpack": { - "optional": true - } - } - }, - "node_modules/html-webpack-plugin/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/html-webpack-plugin/node_modules/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", - "dev": true, - "dependencies": { - "camel-case": "^4.1.2", - "clean-css": "^5.2.2", - "commander": "^8.3.0", - "he": "^1.2.0", - "param-case": "^3.0.4", - "relateurl": "^0.2.7", - "terser": "^5.10.0" - }, - "bin": { - "html-minifier-terser": "cli.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "node_modules/htmlparser2/node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-parser-js": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", - "dev": true - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", - "dev": true, - "dependencies": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@types/express": "^4.17.13" - }, - "peerDependenciesMeta": { - "@types/express": { - "optional": true - } - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/hyperdyperid": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", - "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", - "dev": true, - "engines": { - "node": ">=10.18" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-local": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", - "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/interpret": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", - "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", - "dev": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/ipaddr.js": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", - "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" - }, - "node_modules/is-async-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", - "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", - "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-view": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", - "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", - "dev": true, - "dependencies": { - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", - "dev": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-finalizationregistry": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", - "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-inside-container": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", - "dev": true, - "dependencies": { - "is-docker": "^3.0.0" - }, - "bin": { - "is-inside-container": "cli.js" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-network-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", - "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", - "dev": true, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", - "dev": true, - "dependencies": { - "which-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", - "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-wsl": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", - "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", - "dev": true, - "dependencies": { - "is-inside-container": "^1.0.0" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/iterator.prototype": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", - "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "reflect.getprototypeof": "^1.0.4", - "set-function-name": "^2.0.1" - } - }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-worker/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsx-ast-utils": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", - "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/language-subtag-registry": { - "version": "0.3.23", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", - "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", - "dev": true - }, - "node_modules/language-tags": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", - "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", - "dev": true, - "dependencies": { - "language-subtag-registry": "^0.3.20" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/launch-editor": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.0.tgz", - "integrity": "sha512-vJranOAJrI/llyWGRQqiDM+adrw+k83fvmmx3+nV47g3+36xM15jE+zyZ6Ffel02+xSvuM0b2GDRosXZkbb6wA==", - "dev": true, - "dependencies": { - "picocolors": "^1.0.0", - "shell-quote": "^1.8.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" - }, - "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "engines": { - "node": ">=6.11.5" - } - }, - "node_modules/loader-utils-webpack-v4": { - "name": "loader-utils", - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dependencies": { - "tslib": "^2.0.3" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memfs": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", - "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", - "dev": true, - "dependencies": { - "fs-monkey": "^1.0.4" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", - "dev": true, - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/modify-source-webpack-plugin": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/modify-source-webpack-plugin/-/modify-source-webpack-plugin-4.1.0.tgz", - "integrity": "sha512-UaLQyFXoPWpWxkNUBFo9BotC20CCAGe7HEX9iKtB0P0MgNXgURf9TXUgNGuY5iVV5lDDQtcMjT2vneQWnNmwEw==", - "dev": true, - "dependencies": { - "loader-utils-webpack-v4": "npm:loader-utils@^2.0.4", - "schema-utils": "^4.0.0" - }, - "peerDependencies": { - "webpack": "^4.37.0 || ^5.0.0" - } - }, - "node_modules/modify-source-webpack-plugin/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/modify-source-webpack-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/modify-source-webpack-plugin/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/modify-source-webpack-plugin/node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", - "dev": true, - "dependencies": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" - }, - "bin": { - "multicast-dns": "cli.js" - } - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" - }, - "node_modules/no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dependencies": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - } - }, - "node_modules/node-abort-controller": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", - "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", - "dev": true - }, - "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", - "dev": true, - "engines": { - "node": ">= 6.13.0" - } - }, - "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-is": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", - "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", - "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", - "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.groupby": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", - "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.values": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", - "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/open": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", - "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", - "dev": true, - "dependencies": { - "default-browser": "^5.2.1", - "define-lazy-prop": "^3.0.0", - "is-inside-container": "^1.0.0", - "is-wsl": "^3.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-retry": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz", - "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==", - "dev": true, - "dependencies": { - "@types/retry": "0.12.2", - "is-network-error": "^1.0.0", - "retry": "^0.13.1" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", - "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", - "dev": true - }, - "node_modules/param-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", - "dev": true, - "dependencies": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dev": true, - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/pascal-case": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", - "dev": true, - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true - }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/postcss": { - "version": "8.4.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", - "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.1", - "source-map-js": "^1.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-modules-extract-imports": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", - "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-local-by-default": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", - "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", - "dev": true, - "dependencies": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-scope": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", - "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "dev": true, - "dependencies": { - "icss-utils": "^5.0.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz", - "integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", - "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/pretty-error": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", - "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", - "dev": true, - "dependencies": { - "lodash": "^4.17.20", - "renderkid": "^3.0.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-addr/node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "dev": true, - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/raw-body/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/react-router": { - "version": "6.25.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.25.1.tgz", - "integrity": "sha512-u8ELFr5Z6g02nUtpPAggP73Jigj1mRePSwhS/2nkTrlPU5yEkH1vYzWNyvSnSzeeE2DNqWdH+P8OhIh9wuXhTw==", - "dependencies": { - "@remix-run/router": "1.18.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8" - } - }, - "node_modules/react-router-dom": { - "version": "6.25.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.25.1.tgz", - "integrity": "sha512-0tUDpbFvk35iv+N89dWNrJp+afLgd+y4VtorJZuOCXK0kkCWjEvb3vTJM++SYvMEpbVwXKf3FjeVveVEb6JpDQ==", - "dependencies": { - "@remix-run/router": "1.18.0", - "react-router": "6.25.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/rechoir": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", - "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", - "dev": true, - "dependencies": { - "resolve": "^1.20.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", - "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.1", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", - "which-builtin-type": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", - "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - }, - "node_modules/regenerator-transform": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", - "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpu-core": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", - "dependencies": { - "@babel/regjsgen": "^0.8.0", - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", - "dependencies": { - "jsesc": "~0.5.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "bin": { - "jsesc": "bin/jsesc" - } - }, - "node_modules/relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/renderkid": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", - "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", - "dev": true, - "dependencies": { - "css-select": "^4.1.3", - "dom-converter": "^0.2.0", - "htmlparser2": "^6.1.0", - "lodash": "^4.17.21", - "strip-ansi": "^6.0.1" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", - "integrity": "sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==", - "dev": true, - "dependencies": { - "glob": "^10.3.7" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "engines": { - "node": "14 >=14.20 || 16 >=16.20 || >=18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-applescript": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", - "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-array-concat": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", - "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safe-regex-test": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-regex": "^1.1.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true - }, - "node_modules/selfsigned": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", - "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", - "dev": true, - "dependencies": { - "@types/node-forge": "^1.3.0", - "node-forge": "^1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dev": true, - "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" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", - "dev": true, - "dependencies": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/serve-index/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/serve-index/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-index/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", - "dev": true, - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-index/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true - }, - "node_modules/serve-index/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/serve-index/node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true - }, - "node_modules/serve-index/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dev": true, - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/snake-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", - "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", - "dependencies": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/sockjs": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", - "dev": true, - "dependencies": { - "faye-websocket": "^0.11.3", - "uuid": "^8.3.2", - "websocket-driver": "^0.7.4" - } - }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", - "dev": true, - "dependencies": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "dev": true, - "dependencies": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "dev": true, - "dependencies": { - "internal-slot": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/string.prototype.includes": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.0.tgz", - "integrity": "sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "node_modules/string.prototype.matchall": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", - "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.7", - "regexp.prototype.flags": "^1.5.2", - "set-function-name": "^2.0.2", - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.repeat": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", - "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", - "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", - "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/style-loader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-4.0.0.tgz", - "integrity": "sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA==", - "dev": true, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.27.0" - } - }, - "node_modules/stylis": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", - "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/svg-parser": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", - "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" - }, - "node_modules/svgo": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", - "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", - "dependencies": { - "@trysound/sax": "0.2.0", - "commander": "^7.2.0", - "css-select": "^5.1.0", - "css-tree": "^2.3.1", - "css-what": "^6.1.0", - "csso": "^5.0.5", - "picocolors": "^1.0.0" - }, - "bin": { - "svgo": "bin/svgo" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/svgo" - } - }, - "node_modules/svgo/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "engines": { - "node": ">= 10" - } - }, - "node_modules/svgo/node_modules/css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/svgo/node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/svgo/node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/svgo/node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/synckit": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", - "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", - "dev": true, - "dependencies": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/terser": { - "version": "5.31.3", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.3.tgz", - "integrity": "sha512-pAfYn3NIZLyZpa83ZKigvj6Rn9c/vd5KfYGX7cN1mnzqgDcxWvrU5ZtAfIKhEXz9nRecw4z3LXkjaq96/qZqAA==", - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.10", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", - "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.20", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.26.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/thingies": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", - "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", - "dev": true, - "engines": { - "node": ">=10.18" - }, - "peerDependencies": { - "tslib": "^2" - } - }, - "node_modules/thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tree-dump": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", - "integrity": "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==", - "dev": true, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", - "dev": true, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/ts-loader": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", - "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "enhanced-resolve": "^5.0.0", - "micromatch": "^4.0.0", - "semver": "^7.3.4", - "source-map": "^0.7.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "typescript": "*", - "webpack": "^5.0.0" - } - }, - "node_modules/ts-loader/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/ts-loader/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/ts-loader/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/ts-loader/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/ts-loader/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ts-loader/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ts-loader/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/ts-loader/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", - "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typescript": { - "version": "5.5.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", - "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.17.0.tgz", - "integrity": "sha512-spQxsQvPguduCUfyUvLItvKqK3l8KJ/kqs5Pb/URtzQ5AC53Z6us32St37rpmlt2uESG23lOFpV4UErrmy4dZQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/eslint-plugin": "7.17.0", - "@typescript-eslint/parser": "7.17.0", - "@typescript-eslint/utils": "7.17.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", - "engines": { - "node": ">=4" - } - }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/utila": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", - "dev": true - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/watchpack": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", - "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "dev": true, - "dependencies": { - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/webpack": { - "version": "5.93.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.93.0.tgz", - "integrity": "sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA==", - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.5", - "@webassemblyjs/ast": "^1.12.1", - "@webassemblyjs/wasm-edit": "^1.12.1", - "@webassemblyjs/wasm-parser": "^1.12.1", - "acorn": "^8.7.1", - "acorn-import-attributes": "^1.9.5", - "browserslist": "^4.21.10", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.0", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.10", - "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-cli": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", - "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", - "dev": true, - "dependencies": { - "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^2.1.1", - "@webpack-cli/info": "^2.0.2", - "@webpack-cli/serve": "^2.0.5", - "colorette": "^2.0.14", - "commander": "^10.0.1", - "cross-spawn": "^7.0.3", - "envinfo": "^7.7.3", - "fastest-levenshtein": "^1.0.12", - "import-local": "^3.0.2", - "interpret": "^3.1.1", - "rechoir": "^0.8.0", - "webpack-merge": "^5.7.3" - }, - "bin": { - "webpack-cli": "bin/cli.js" - }, - "engines": { - "node": ">=14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "5.x.x" - }, - "peerDependenciesMeta": { - "@webpack-cli/generators": { - "optional": true - }, - "webpack-bundle-analyzer": { - "optional": true - }, - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/webpack-dev-middleware": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.3.0.tgz", - "integrity": "sha512-xD2qnNew+F6KwOGZR7kWdbIou/ud7cVqLEXeK1q0nHcNsX/u7ul/fSdlOTX4ntSL5FNFy7ZJJXbf0piF591JYw==", - "dev": true, - "dependencies": { - "colorette": "^2.0.10", - "memfs": "^4.6.0", - "mime-types": "^2.1.31", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - } - } - }, - "node_modules/webpack-dev-middleware/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/webpack-dev-middleware/node_modules/memfs": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.9.3.tgz", - "integrity": "sha512-bsYSSnirtYTWi1+OPMFb0M048evMKyUYe0EbtuGQgq6BVQM1g1W8/KIUJCCvjgI/El0j6Q4WsmMiBwLUBSw8LA==", - "dev": true, - "dependencies": { - "@jsonjoy.com/json-pack": "^1.0.3", - "@jsonjoy.com/util": "^1.1.2", - "tree-dump": "^1.0.1", - "tslib": "^2.0.0" - }, - "engines": { - "node": ">= 4.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - } - }, - "node_modules/webpack-dev-middleware/node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/webpack-dev-server": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.0.4.tgz", - "integrity": "sha512-dljXhUgx3HqKP2d8J/fUMvhxGhzjeNVarDLcbO/EWMSgRizDkxHQDZQaLFL5VJY9tRBj2Gz+rvCEYYvhbqPHNA==", - "dev": true, - "dependencies": { - "@types/bonjour": "^3.5.13", - "@types/connect-history-api-fallback": "^1.5.4", - "@types/express": "^4.17.21", - "@types/serve-index": "^1.9.4", - "@types/serve-static": "^1.15.5", - "@types/sockjs": "^0.3.36", - "@types/ws": "^8.5.10", - "ansi-html-community": "^0.0.8", - "bonjour-service": "^1.2.1", - "chokidar": "^3.6.0", - "colorette": "^2.0.10", - "compression": "^1.7.4", - "connect-history-api-fallback": "^2.0.0", - "default-gateway": "^6.0.3", - "express": "^4.17.3", - "graceful-fs": "^4.2.6", - "html-entities": "^2.4.0", - "http-proxy-middleware": "^2.0.3", - "ipaddr.js": "^2.1.0", - "launch-editor": "^2.6.1", - "open": "^10.0.3", - "p-retry": "^6.2.0", - "rimraf": "^5.0.5", - "schema-utils": "^4.2.0", - "selfsigned": "^2.4.1", - "serve-index": "^1.9.1", - "sockjs": "^0.3.24", - "spdy": "^4.0.2", - "webpack-dev-middleware": "^7.1.0", - "ws": "^8.16.0" - }, - "bin": { - "webpack-dev-server": "bin/webpack-dev-server.js" - }, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - }, - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-dev-server/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack-dev-server/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/webpack-dev-server/node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/webpack-merge": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", - "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", - "dev": true, - "dependencies": { - "clone-deep": "^4.0.1", - "flat": "^5.0.2", - "wildcard": "^2.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/webpack/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "dev": true, - "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", - "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", - "dev": true, - "dependencies": { - "function.prototype.name": "^1.1.5", - "has-tostringtag": "^1.0.0", - "is-async-function": "^2.0.0", - "is-date-object": "^1.0.5", - "is-finalizationregistry": "^1.0.2", - "is-generator-function": "^1.0.10", - "is-regex": "^1.1.4", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", - "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", - "dev": true, - "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/wildcard": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", - "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", - "dev": true - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/client/package.json b/client/package.json deleted file mode 100644 index cb8e9a714..000000000 --- a/client/package.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "name": "haengdong-client", - "version": "1.0.0", - "description": "", - "type": "module", - "scripts": { - "start": "webpack serve ", - "build": "webpack --mode production", - "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'", - "format": "prettier --write 'src/**/*.{js,jsx,ts,tsx,json,css,scss,md}'" - }, - "keywords": [], - "author": "", - "license": "ISC", - "devDependencies": { - "@eslint/compat": "^1.1.0", - "@eslint/js": "^9.6.0", - "@svgr/webpack": "^8.1.0", - "@types/react": "^18.3.3", - "@types/react-dom": "^18.3.0", - "@typescript-eslint/eslint-plugin": "^7.16.0", - "@typescript-eslint/parser": "^7.16.0", - "css-loader": "^7.1.2", - "dotenv": "^16.4.5", - "eslint": "^9.6.0", - "eslint-import-resolver-typescript": "^3.6.1", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jsx-a11y": "^6.9.0", - "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-react": "^7.34.3", - "eslint-plugin-react-hooks": "^4.6.2", - "fork-ts-checker-webpack-plugin": "^9.0.2", - "globals": "^15.8.0", - "html-loader": "^5.0.0", - "html-webpack-plugin": "^5.6.0", - "modify-source-webpack-plugin": "^4.1.0", - "prettier": "3.3.2", - "style-loader": "^4.0.0", - "ts-loader": "^9.5.1", - "typescript": "^5.5.3", - "typescript-eslint": "^7.16.0", - "webpack": "^5.93.0", - "webpack-cli": "^5.1.4", - "webpack-dev-server": "^5.0.4" - }, - "dependencies": { - "@emotion/react": "^11.11.4", - "@types/dotenv-webpack": "^7.0.7", - "dotenv-webpack": "^8.1.0", - "haengdong-design": "^0.1.35", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "react-router-dom": "^6.24.1" - }, - "engines": { - "npm": ">=10.7.0", - "node": ">=20.15.1" - } -} \ No newline at end of file diff --git a/client/src/App.tsx b/client/src/App.tsx deleted file mode 100644 index 46618d881..000000000 --- a/client/src/App.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import {HDesignProvider} from 'haengdong-design'; -import {Outlet} from 'react-router-dom'; - -const App: React.FC = () => { - return ( - - - - ); -}; - -export default App; diff --git a/client/src/apis/baseUrl.ts b/client/src/apis/baseUrl.ts deleted file mode 100644 index e508ba375..000000000 --- a/client/src/apis/baseUrl.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const BASE_URL = { - HD: process.env.API_BASE_URL ?? '', -}; diff --git a/client/src/apis/fetcher.ts b/client/src/apis/fetcher.ts deleted file mode 100644 index f0bdb9887..000000000 --- a/client/src/apis/fetcher.ts +++ /dev/null @@ -1,136 +0,0 @@ -type Method = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE'; - -type Body = ReadableStream | XMLHttpRequestBodyInit; -type HeadersType = [string, string][] | Record | Headers; - -export type ObjectQueryParams = Record; - -type RequestProps = { - baseUrl?: string; - endpoint: string; - headers?: HeadersType; - body?: Body | object | null; - queryParams?: ObjectQueryParams; - // errorMessage: string; -}; - -type FetcherProps = RequestProps & { - method: Method; -}; - -type Options = { - method: Method; - headers: HeadersType; - body?: Body | null; -}; - -const API_BASE_URL = process.env.API_BASE_URL; - -const objectToQueryString = (params: ObjectQueryParams): string => { - return Object.entries(params) - .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`) - .join('&'); -}; - -export const requestGet = async ({headers = {}, ...args}: RequestProps): Promise => { - const response = await fetcher({ - ...args, - method: 'GET', - headers, - }); - - const data: T = await response!.json(); - return data; -}; - -export const requestPatch = ({headers = {}, ...args}: RequestProps) => { - return fetcher({method: 'PATCH', headers, ...args}); -}; - -export const requestPut = ({headers = {}, ...args}: RequestProps) => { - return fetcher({method: 'PUT', headers, ...args}); -}; - -export const requestPost = async ({headers = {}, ...args}: RequestProps): Promise => { - const response = await fetcher({method: 'POST', headers, ...args}); - - const contentType = response!.headers.get('Content-Type'); - if (contentType && contentType.includes('application/json')) { - const data: T = await response!.json(); - return data; - } - - return; -}; - -export const requestDelete = ({headers = {}, ...args}: RequestProps) => { - return fetcher({method: 'DELETE', headers, ...args}); -}; - -const fetcher = ({baseUrl = API_BASE_URL, method, endpoint, headers, body, queryParams}: FetcherProps) => { - // const token = generateBasicToken(USER_ID, USER_PASSWORD); - const options = { - method, - headers: { - 'Content-Type': 'application/json', - // Authorization: token, - ...headers, - }, - body: body ? JSON.stringify(body) : null, - }; - - let url = `${baseUrl}${endpoint}`; - - if (queryParams) url += `?${objectToQueryString(queryParams)}`; - - return errorHandler(url, options); -}; - -// class ErrorWithHeader extends Error { -// header: string; - -// constructor(header: string, message: string) { -// super(message); -// this.name = this.constructor.name; -// this.header = header; -// } -// } - -const errorHandler = async (url: string, options: Options) => { - try { - const response = await fetch(url, options); - if (!response.ok) { - const serverErrorMessage = await response.text(); - throw new Error(serverErrorMessage || ''); // 받은 에러 메세지가 없는 경우는 서버에게.. - } - return response; - } catch (error) { - console.error(error); - // throw new ErrorWithHeader(errorMessageHeader, getErrorMessage(error)); - return; - } -}; - -// export const ERROR_MESSAGE = { -// SYSTEM_FAULT: 'system error. 관리자에게 문의하십시오', -// OFFLINE: '네트워크 연결이 끊어졌습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.', -// UNKNOWN: '알 수 없는 에러입니다. 관리자에게 문의해주세요. (연락처...)', -// }; - -// const getErrorMessage = (error: unknown) => { -// return ERROR_MESSAGE.UNKNOWN; - -// if (error instanceof TypeError) return ERROR_MESSAGE.OFFLINE; - -// if (error instanceof Error) { -// const mappedErrorMessage = Object.entries(SERVER_ERROR_MESSAGE).find(([key]) => { -// const upperCaseErrorMessage = convertToUpperCase(error.message.split(SERVER_ERROR_MESSAGE_DIVIDER)[0]); - -// return upperCaseErrorMessage.includes(key); -// })?.[1]; - -// return mappedErrorMessage ?? ERROR_MESSAGE.UNKNOWN; -// } - -// return ERROR_MESSAGE.UNKNOWN; -// }; diff --git a/client/src/apis/request/bill.ts b/client/src/apis/request/bill.ts deleted file mode 100644 index c07fd758a..000000000 --- a/client/src/apis/request/bill.ts +++ /dev/null @@ -1,18 +0,0 @@ -import {BASE_URL} from '@apis/baseUrl'; -import {TEMP_PREFIX} from '@apis/tempPrefix'; -import {requestPost} from '@apis/fetcher'; -import {WithEventId} from '@apis/withEventId.type'; - -type RequestAddBillList = { - billList: Bill[]; -}; - -export const requestAddBillList = async ({eventId, billList}: WithEventId) => { - await requestPost({ - baseUrl: BASE_URL.HD, - endpoint: `${TEMP_PREFIX}/${eventId}/actions/bills`, - body: { - actions: billList, - }, - }); -}; diff --git a/client/src/apis/request/event.ts b/client/src/apis/request/event.ts deleted file mode 100644 index 5822267b9..000000000 --- a/client/src/apis/request/event.ts +++ /dev/null @@ -1,29 +0,0 @@ -import {TEMP_PREFIX} from '@apis/tempPrefix'; -import {requestGet, requestPost} from '@apis/fetcher'; -import {WithEventId} from '@apis/withEventId.type'; - -type RequestCreateNewEvent = { - eventName: string; -}; - -type ResponseCreateNewEvent = { - eventId: string; -}; - -export const requestCreateNewEvent = async ({eventName}: RequestCreateNewEvent) => { - // TODO: (@weadie) 뼈대만 둔 것. header값을 꺼내오는 로직이 필요하다. 또는 바디에 달라고 부탁할 수 있다. - return requestPost({ - endpoint: TEMP_PREFIX, - body: {eventName}, - }); -}; - -type ResponseGetEventName = { - eventName: string; -}; - -export const requestGetEventName = async ({eventId}: WithEventId) => { - return requestGet({ - endpoint: `${TEMP_PREFIX}/${eventId}`, - }); -}; diff --git a/client/src/apis/request/member.ts b/client/src/apis/request/member.ts deleted file mode 100644 index d23563f34..000000000 --- a/client/src/apis/request/member.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {BASE_URL} from '@apis/baseUrl'; -import {TEMP_PREFIX} from '@apis/tempPrefix'; -import {requestPost} from '@apis/fetcher'; -import {WithEventId} from '@apis/withEventId.type'; - -type RequestUpdateMemberList = { - memberNameList: string[]; - type: MemberType; -}; - -export const requestUpdateMemberList = async ({ - eventId, - type, - memberNameList, -}: WithEventId) => { - await requestPost({ - baseUrl: BASE_URL.HD, - endpoint: `${TEMP_PREFIX}/${eventId}/actions/members`, - body: { - members: memberNameList, - status: type, - }, - }); -}; diff --git a/client/src/apis/request/report.ts b/client/src/apis/request/report.ts deleted file mode 100644 index faa6c9185..000000000 --- a/client/src/apis/request/report.ts +++ /dev/null @@ -1,17 +0,0 @@ -import {BASE_URL} from '@apis/baseUrl'; -import {TEMP_PREFIX} from '@apis/tempPrefix'; -import {requestGet} from '@apis/fetcher'; -import {WithEventId} from '@apis/withEventId.type'; - -type ResponseMemberReportList = { - reports: MemberReport[]; -}; - -export const requestMemberReportList = async ({eventId}: WithEventId) => { - const {reports} = await requestGet({ - baseUrl: BASE_URL.HD, - endpoint: `${TEMP_PREFIX}/${eventId}/actions/reports`, - }); - - return reports; -}; diff --git a/client/src/apis/request/stepList.ts b/client/src/apis/request/stepList.ts deleted file mode 100644 index e09cb67fd..000000000 --- a/client/src/apis/request/stepList.ts +++ /dev/null @@ -1,15 +0,0 @@ -import {BASE_URL} from '@apis/baseUrl'; -import {TEMP_PREFIX} from '@apis/tempPrefix'; -import {requestGet} from '@apis/fetcher'; -import {WithEventId} from '@apis/withEventId.type'; - -// TODO: (@weadie) 현재 토큰을 어떻게 관리할지.. 계속 사용되는데 -export const requestStepList = async ({eventId}: WithEventId) => { - // TODO: (@weadie) response가 어떻게 오는지 안나와서 data로만 써뒀어요. - const {steps} = await requestGet({ - baseUrl: BASE_URL.HD, - endpoint: `${TEMP_PREFIX}/${eventId}/actions`, - }); - - return steps; -}; diff --git a/client/src/apis/requestPostEvent.ts b/client/src/apis/requestPostEvent.ts deleted file mode 100644 index c03ae02af..000000000 --- a/client/src/apis/requestPostEvent.ts +++ /dev/null @@ -1,13 +0,0 @@ -import {requestPost} from './fetcher'; - -interface RequestPostEventProps { - name: string; -} - -export const requestPostEvent = async ({name}: RequestPostEventProps) => { - await requestPost({ - headers: {'Content-Type': 'application/json'}, - body: {name}, - endpoint: '/api/events', - }); -}; diff --git a/client/src/apis/tempPrefix.ts b/client/src/apis/tempPrefix.ts deleted file mode 100644 index 949981b73..000000000 --- a/client/src/apis/tempPrefix.ts +++ /dev/null @@ -1,2 +0,0 @@ -// TODO: (@weadie) 반복되서 쓰이는 이 api/events가 추후 수정 가능성이 있어서 일단 편집하기 편하게 이 변수를 재사용하도록 했습니다. -export const TEMP_PREFIX = '/api/events'; diff --git a/client/src/apis/withEventId.type.ts b/client/src/apis/withEventId.type.ts deleted file mode 100644 index b88160e3e..000000000 --- a/client/src/apis/withEventId.type.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type WithEventId

= P & { - eventId: string; -}; diff --git a/client/src/components/MemberReportList/MemberReportList.tsx b/client/src/components/MemberReportList/MemberReportList.tsx deleted file mode 100644 index 1004540fa..000000000 --- a/client/src/components/MemberReportList/MemberReportList.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import {ExpenseList, Flex, Input} from 'haengdong-design'; -import React, {useState} from 'react'; - -import useSearchMemberReportList from '@hooks/useSearchMemberReportList/useSearchMemberReportList'; - -const MemberReportList = () => { - const [name, setName] = useState(''); - const {memberReportSearchList} = useSearchMemberReportList({name}); - - const changeName = ({target}: React.ChangeEvent) => { - setName(target.value); - }; - - return ( - - - - - ); -}; - -export default MemberReportList; diff --git a/client/src/components/Modal/Modal.style.ts b/client/src/components/Modal/Modal.style.ts deleted file mode 100644 index 727d0482f..000000000 --- a/client/src/components/Modal/Modal.style.ts +++ /dev/null @@ -1,23 +0,0 @@ -import {css} from '@emotion/react'; - -export const modalBodyStyle = css` - z-index: 100; - background-color: white; - position: fixed; - bottom: 0; - left: 0; - right: 0; - padding: 20px; - border-radius: 20px 20px 0 0; - box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1); -`; - -export const modalBackdropStyle = css` - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgba(0, 0, 0, 0.5); - z-index: 99; -`; diff --git a/client/src/components/Modal/SetActionModalContent/SetActionModalContent.style.ts b/client/src/components/Modal/SetActionModalContent/SetActionModalContent.style.ts deleted file mode 100644 index 560f672d5..000000000 --- a/client/src/components/Modal/SetActionModalContent/SetActionModalContent.style.ts +++ /dev/null @@ -1,16 +0,0 @@ -import {css} from '@emotion/react'; - -export const setActionModalContentStyle = css({ - display: 'flex', - flexDirection: 'column', - width: '100%', - height: '100%', - padding: '0 1.5rem', - gap: '1.5rem', -}); - -export const setActionModalContentSwitchContainerStyle = css({ - display: 'flex', - width: '100%', - justifyContent: 'space-between', -}); diff --git a/client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx b/client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx deleted file mode 100644 index b3ccd64c9..000000000 --- a/client/src/components/Modal/SetActionModalContent/SetActionModalContent.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import {useState} from 'react'; -import {BottomSheet, Switch} from 'haengdong-design'; - -import SetPurchase from './SetPurchase'; -import UpdateParticipants from './UpdateParticipants'; -import {setActionModalContentStyle, setActionModalContentSwitchContainerStyle} from './SetActionModalContent.style'; - -export type ActionType = '지출' | '인원'; - -interface SetActionModalContentProps { - openBottomSheet: boolean; - setOpenBottomSheet: React.Dispatch>; - setOrder: React.Dispatch>; -} - -const SetActionModalContent = ({openBottomSheet, setOpenBottomSheet, setOrder}: SetActionModalContentProps) => { - const [action, setAction] = useState('지출'); - const [inOutAction, setInOutAction] = useState('탈주'); - - const handleActionTypeChange = (value: string) => { - setAction(value as ActionType); - }; - - const handleParticipantTypeChange = (value: string) => { - setInOutAction(value as InOutType); - }; - - return ( - setOpenBottomSheet(false)}> -

-
- - {action === '인원' && ( - - )} -
- - {action === '지출' && } - {action === '인원' && ( - - )} -
- - ); -}; - -export default SetActionModalContent; diff --git a/client/src/components/Modal/SetActionModalContent/SetPurchase.style.ts b/client/src/components/Modal/SetActionModalContent/SetPurchase.style.ts deleted file mode 100644 index cc852da28..000000000 --- a/client/src/components/Modal/SetActionModalContent/SetPurchase.style.ts +++ /dev/null @@ -1,23 +0,0 @@ -import {css} from '@emotion/react'; - -export const setPurchaseStyle = () => - css({ - height: '100%', - }); - -export const setPurchaseInputContainerStyle = () => - css({ - display: 'flex', - height: '100%', - flexDirection: 'column', - gap: '1.5rem', - overflow: 'auto', - paddingBottom: '14rem', - }); - -export const setPurchaseInputStyle = () => - css({ - display: 'flex', - flexDirection: 'column', - gap: '0.5rem', - }); diff --git a/client/src/components/Modal/SetActionModalContent/SetPurchase.tsx b/client/src/components/Modal/SetActionModalContent/SetPurchase.tsx deleted file mode 100644 index a83a697a7..000000000 --- a/client/src/components/Modal/SetActionModalContent/SetPurchase.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import {Input, FixedButton} from 'haengdong-design'; - -import {useStepList} from '@hooks/useStepList/useStepList'; - -import useDynamicInputPairs from '@hooks/useDynamicInputPairs'; - -import {setPurchaseInputStyle, setPurchaseStyle, setPurchaseInputContainerStyle} from './SetPurchase.style'; - -interface SetPurchaseProps { - setOpenBottomSheet: React.Dispatch>; - setOrder: React.Dispatch>; -} - -const SetPurchase = ({setOpenBottomSheet, setOrder}: SetPurchaseProps) => { - const {inputPairs, inputRefs, handleInputChange, handleInputBlur, getNonEmptyInputPairs} = useDynamicInputPairs(); - const {addBill} = useStepList(); - - const handleSetPurchaseSubmit = () => { - setOrder(prev => prev + 1); - - // TODO: (@weadie) 요청 실패시 오류 핸들 필요 - addBill(getNonEmptyInputPairs()); - setOpenBottomSheet(false); - }; - - return ( -
-
- {inputPairs.map((pair, index) => ( -
- handleInputChange(index, 'title', e.target.value)} - onBlur={() => handleInputBlur(index)} - placeholder="지출 내역" - ref={el => (inputRefs.current[index * 2] = el)} - /> - handleInputChange(index, 'price', e.target.value)} - onBlur={() => handleInputBlur(index)} - placeholder="금액" - ref={el => (inputRefs.current[index * 2 + 1] = el)} - /> -
- ))} -
- -
- ); -}; - -export default SetPurchase; diff --git a/client/src/components/Modal/SetActionModalContent/UpdateParticipants.style.ts b/client/src/components/Modal/SetActionModalContent/UpdateParticipants.style.ts deleted file mode 100644 index 087e25a85..000000000 --- a/client/src/components/Modal/SetActionModalContent/UpdateParticipants.style.ts +++ /dev/null @@ -1,18 +0,0 @@ -import {css} from '@emotion/react'; - -export const updateParticipantsStyle = () => - css({ - display: 'flex', - flexDirection: 'column', - gap: '1.5rem', - height: '100%', - }); - -export const updateParticipantsInputStyle = () => - css({ - display: 'flex', - flexDirection: 'column', - gap: '1rem', - overflow: 'auto', - paddingBottom: '14rem', - }); diff --git a/client/src/components/Modal/SetActionModalContent/UpdateParticipants.tsx b/client/src/components/Modal/SetActionModalContent/UpdateParticipants.tsx deleted file mode 100644 index 5adc3cd43..000000000 --- a/client/src/components/Modal/SetActionModalContent/UpdateParticipants.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import {Input, FixedButton} from 'haengdong-design'; - -import {useStepList} from '@hooks/useStepList/useStepList'; - -import useDynamicInput from '@hooks/useDynamicAdditionalInput'; - -import {updateParticipantsInputStyle, updateParticipantsStyle} from './UpdateParticipants.style'; - -interface UpdateParticipantsProps { - inOutAction: MemberType; - setOpenBottomSheet: React.Dispatch>; -} - -const UpdateParticipants = ({inOutAction, setOpenBottomSheet}: UpdateParticipantsProps) => { - const {inputs, inputRefs, handleInputChange, handleInputBlur, getNonEmptyInputs} = useDynamicInput(); - const {updateMemberList} = useStepList(); - - const handleUpdateParticipantsSubmit = () => { - updateMemberList({memberNameList: getNonEmptyInputs(), type: inOutAction}); - setOpenBottomSheet(false); - }; - - return ( -
-
- {/* TODO: (@soha) Search로 변경하기 */} - {inputs.map((name, index) => ( - (inputRefs.current[index] = el)} - onChange={e => handleInputChange(index, e.target.value)} - onBlur={() => handleInputBlur(index)} - /> - ))} -
- -
- ); -}; - -export default UpdateParticipants; diff --git a/client/src/components/Modal/SetActionModalContent/index.ts b/client/src/components/Modal/SetActionModalContent/index.ts deleted file mode 100644 index c7514135c..000000000 --- a/client/src/components/Modal/SetActionModalContent/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {default as SetActionModalContent} from './SetActionModalContent'; diff --git a/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.style.ts b/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.style.ts deleted file mode 100644 index f0f5bf996..000000000 --- a/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.style.ts +++ /dev/null @@ -1,20 +0,0 @@ -import {css} from '@emotion/react'; - -export const setInitialParticipantsStyle = () => - css({ - display: 'flex', - flexDirection: 'column', - gap: '1.5rem', - width: '100%', - height: '100%', - padding: '0 1.5rem', - }); - -export const setInitialParticipantsInputGroupStyle = () => - css({ - display: 'flex', - flexDirection: 'column', - gap: '1rem', - overflow: 'auto', - paddingBottom: '11rem', - }); diff --git a/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.tsx b/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.tsx deleted file mode 100644 index e5dda7c96..000000000 --- a/client/src/components/Modal/SetInitialParticipants/SetInitialParticipants.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import {Text, Input, BottomSheet, FixedButton} from 'haengdong-design'; - -import {useStepList} from '@hooks/useStepList/useStepList'; - -import useDynamicInput from '@hooks/useDynamicAdditionalInput'; - -import {setInitialParticipantsInputGroupStyle, setInitialParticipantsStyle} from './SetInitialParticipants.style'; - -interface SetInitialParticipantsProps { - openBottomSheet: boolean; - setOpenBottomSheet: React.Dispatch>; -} - -const SetInitialParticipants = ({openBottomSheet, setOpenBottomSheet}: SetInitialParticipantsProps) => { - const {inputs, inputRefs, handleInputChange, handleInputBlur, getNonEmptyInputs} = useDynamicInput(); - const {updateMemberList} = useStepList(); - - const handleSubmit = () => { - updateMemberList({memberNameList: getNonEmptyInputs(), type: 'IN'}); - setOpenBottomSheet(false); - }; - - return ( - setOpenBottomSheet(false)}> -
- 초기 인원 설정하기 -
- {inputs.map((participant, index) => ( - (inputRefs.current[index] = el)} - onChange={e => handleInputChange(index, e.target.value)} - onBlur={() => handleInputBlur(index)} - /> - ))} -
-
- -
- ); -}; - -export default SetInitialParticipants; diff --git a/client/src/components/Modal/SetInitialParticipants/index.ts b/client/src/components/Modal/SetInitialParticipants/index.ts deleted file mode 100644 index c41b6a206..000000000 --- a/client/src/components/Modal/SetInitialParticipants/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {default as SetInitialParticipants} from './SetInitialParticipants'; diff --git a/client/src/components/Modal/index.ts b/client/src/components/Modal/index.ts deleted file mode 100644 index e5d5264cd..000000000 --- a/client/src/components/Modal/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export {default as SetInitialParticipants} from './SetInitialParticipants/SetInitialParticipants'; -export {default as SetActionModalContent} from './SetActionModalContent/SetActionModalContent'; diff --git a/client/src/components/StepList/StepList.tsx b/client/src/components/StepList/StepList.tsx deleted file mode 100644 index 6e9961f99..000000000 --- a/client/src/components/StepList/StepList.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import {Flex, InOutItem, StepItem} from 'haengdong-design'; - -import {useStepList} from '@hooks/useStepList/useStepList'; - -const StepList = () => { - const {stepList} = useStepList(); - - // TODO: (@weadie) if else 구문이 지저분하므로 리펙터링이 필요합니다. - return ( - - {stepList.map(step => { - if (step.type === 'BILL') { - return ( - - ); - } else if (step.type === 'IN' || step.type === 'OUT') { - return name)} />; - } else { - return <>; - } - })} - - ); -}; - -export default StepList; diff --git a/client/src/constants/routerUrls.ts b/client/src/constants/routerUrls.ts deleted file mode 100644 index c57ab181e..000000000 --- a/client/src/constants/routerUrls.ts +++ /dev/null @@ -1,8 +0,0 @@ -export const ROUTER_URLS = { - main: '', - eventCreateName: '/event/create/name', - eventCreateComplete: '/event/create/complete', - event: '/event', // TODO: (@weadie) baseurl을 어떻게 관리할 것인가? - eventManage: '/event/:eventId/admin', - home: '/event/:eventId/home', -}; diff --git a/client/src/hooks/useDynamicAdditionalInput.tsx b/client/src/hooks/useDynamicAdditionalInput.tsx deleted file mode 100644 index 6bd592254..000000000 --- a/client/src/hooks/useDynamicAdditionalInput.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import {useEffect, useRef, useState} from 'react'; - -const useDynamicInput = () => { - const [inputs, setInputs] = useState(['']); - const inputRefs = useRef<(HTMLInputElement | null)[]>([]); - - // TODO: (@soha) 입력이 완료되고 중간에 값을 모두 지웠을 경우 Input이 없애지도록 수정하기 - const handleInputChange = (index: number, value: string) => { - const newInputs = [...inputs]; - newInputs[index] = value; - setInputs(newInputs); - }; - - const handleInputBlur = (index: number) => { - if (inputs[index].trim() === '') { - setInputs(prev => { - const newInputs = [...prev]; - newInputs[index] = ''; - return newInputs; - }); - } else if (inputs[index].trim() !== '' && index === inputs.length - 1) { - setInputs(prev => { - const newInputs = [...prev, '']; - newInputs[index] = inputs[index].trim(); - return newInputs; - }); - } - }; - - const getNonEmptyInputs = () => { - return inputs.filter(input => input.trim() !== ''); - }; - - useEffect(() => { - if (inputRefs.current.length > 0) { - const lastInput = inputRefs.current[inputRefs.current.length - 1]; - if (lastInput) { - lastInput.scrollIntoView({behavior: 'smooth', block: 'center'}); - } - } - }, [inputs]); - - return { - inputs, - inputRefs, - handleInputChange, - handleInputBlur, - getNonEmptyInputs, - }; -}; - -export default useDynamicInput; diff --git a/client/src/hooks/useDynamicInputPairs.tsx b/client/src/hooks/useDynamicInputPairs.tsx deleted file mode 100644 index b6f86b000..000000000 --- a/client/src/hooks/useDynamicInputPairs.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import {useEffect, useRef, useState} from 'react'; - -const useDynamicInputPairs = () => { - const [inputPairs, setInputPairs] = useState([{title: '', price: 0}]); - const inputRefs = useRef<(HTMLInputElement | null)[]>([]); - - const handleInputChange = (index: number, field: 'title' | 'price', value: string) => { - const newInputPairs = [...inputPairs]; - newInputPairs[index] = { - ...newInputPairs[index], - [field]: field === 'price' ? parseFloat(value) : value, - }; - setInputPairs(newInputPairs); - }; - - const handleInputBlur = (index: number) => { - const currentPair = inputPairs[index]; - if (currentPair.title.trim() === '' && currentPair.price === 0) { - setInputPairs(prev => prev.filter((_, i) => i !== index)); - } else if (currentPair.title.trim() !== '' && currentPair.price !== 0 && index === inputPairs.length - 1) { - setInputPairs(prev => [...prev, {title: '', price: 0}]); - } - }; - - const getNonEmptyInputPairs = () => { - return inputPairs.filter(currentPair => currentPair.title.trim() !== '' && currentPair.price !== 0); - }; - - useEffect(() => { - if (inputRefs.current.length > 0) { - const lastInputPair = inputRefs.current.slice(-2); - lastInputPair.forEach(ref => ref?.scrollIntoView({behavior: 'smooth', block: 'center'})); - } - }, [inputPairs]); - - return { - inputPairs, - getNonEmptyInputPairs, - inputRefs, - handleInputChange, - handleInputBlur, - }; -}; - -export default useDynamicInputPairs; diff --git a/client/src/hooks/useEventId/useEventId.tsx b/client/src/hooks/useEventId/useEventId.tsx deleted file mode 100644 index ca3775f8e..000000000 --- a/client/src/hooks/useEventId/useEventId.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import {useEffect, useState} from 'react'; -import {useLocation} from 'react-router-dom'; - -const useEventId = () => { - const [eventId, setEventId] = useState(''); - const location = useLocation(); - - const extractIdFromUrl = (url: string) => { - const regex = /\/event\/([a-zA-Z0-9-]+)\//; - const match = url.match(regex); - return match ? match[1] : null; - }; - - const curEventId = extractIdFromUrl(location.pathname) ?? ''; - - useEffect(() => { - setEventId(curEventId); - }, []); - - return { - eventId, - }; -}; - -export default useEventId; diff --git a/client/src/hooks/useNavSwitch.tsx b/client/src/hooks/useNavSwitch.tsx deleted file mode 100644 index 7ecd3def8..000000000 --- a/client/src/hooks/useNavSwitch.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import {useState} from 'react'; -import {useLocation, useNavigate} from 'react-router-dom'; - -const PATH_TABLE: Record = { - 홈: 'home', - 관리: 'admin', -}; - -const PATH_DISPLAY_TABLE: Record = { - home: '홈', - admin: '관리', -}; - -const useNavSwitch = () => { - const paths = ['홈', '관리']; - const location = useLocation(); - const navigate = useNavigate(); - - const pathArray = location.pathname.split('/'); - const basePath = pathArray.slice(0, -1).join('/'); - const lastPath = pathArray[pathArray.length - 1]; - - const [nav, setNav] = useState(PATH_DISPLAY_TABLE[lastPath]); - - const onChange = (displayName: string) => { - setNav(displayName); - navigate(`${basePath}/${PATH_TABLE[displayName]}`); - }; - - return { - nav, - paths, - onChange, - }; -}; - -export default useNavSwitch; diff --git a/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.tsx b/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.tsx deleted file mode 100644 index 02c07b80a..000000000 --- a/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import {useEffect, useState} from 'react'; - -import {requestMemberReportList} from '@apis/request/report'; -import useEventId from '@hooks/useEventId/useEventId'; - -type UseSearchMemberReportListParams = { - name: string; -}; - -const useSearchMemberReportList = ({name}: UseSearchMemberReportListParams) => { - const [memberReportList, setMemberReportList] = useState([]); - const [memberReportSearchList, setMemberReportSearchList] = useState([]); - const {eventId} = useEventId(); - - useEffect(() => { - const fetchMemberReportList = async () => { - // TODO: (@weadie) cors 고쳐지면 주석 풀게요. - // TODO: (@weadie) eventId에 의존하는 두 개의 훅에 대한 리펙토링 필요 - if (eventId === '') return; - - const memberReportListData = await requestMemberReportList({eventId}); - - setMemberReportList(memberReportListData); - }; - - fetchMemberReportList(); - }, [eventId]); - - // TODO: (@weadie) 글자가 완성될 때마다 아래 로직이 실행되어야 합니다. - useEffect(() => { - if (name === '') setMemberReportSearchList(memberReportList); - - setMemberReportSearchList(memberReportList.filter(memberReport => memberReport.name.includes(name))); - }, [name, memberReportList]); - - return { - memberReportSearchList, - }; -}; - -export default useSearchMemberReportList; diff --git a/client/src/hooks/useStepList/type.ts b/client/src/hooks/useStepList/type.ts deleted file mode 100644 index 6d9b78de1..000000000 --- a/client/src/hooks/useStepList/type.ts +++ /dev/null @@ -1,38 +0,0 @@ -export type Step = { - type: MemberType | 'BILL'; - stepName: string | null; - members: string[]; - actions: (BillAction | MemberAction)[]; -}; - -export type MemberStep = Omit & { - type: MemberType; - stepName: null; - actions: MemberAction[]; -}; - -export type BillStep = Omit & { - type: 'BILL'; - stepName: string; - actions: BillAction[]; -}; - -export type Action = { - actionId: number; - name: string; - price: number | null; - sequence?: number; -}; - -export type BillAction = Omit & { - price: number; -}; - -export type MemberAction = Omit & { - price: null; -}; - -export type Member = { - name: string; - status: MemberType; -}; diff --git a/client/src/hooks/useStepList/useStepList.tsx b/client/src/hooks/useStepList/useStepList.tsx deleted file mode 100644 index 52d2a78d6..000000000 --- a/client/src/hooks/useStepList/useStepList.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import {PropsWithChildren, createContext, useContext, useEffect, useState} from 'react'; - -import useEventId from '@hooks/useEventId/useEventId'; -import {requestAddBillList} from '@apis/request/bill'; -import {requestUpdateMemberList} from '@apis/request/member'; -import {requestStepList} from '@apis/request/stepList'; - -import {BillAction, BillStep, MemberStep} from './type.ts'; - -interface StepListContextProps { - stepList: (BillStep | MemberStep)[]; - getTotalPrice: () => number; - addBill: (billList: Bill[]) => Promise; - updateMemberList: ({type, memberNameList}: {type: MemberType; memberNameList: string[]}) => Promise; - memberNameList: string[]; -} - -export const StepListContext = createContext(null); // TODO: (@weadie) 인자를 어떻게 줘야 하는지 고민하기. - -const StepListProvider = ({children}: PropsWithChildren) => { - const [stepList, setStepList] = useState<(BillStep | MemberStep)[]>([]); - const [memberNameList, setNameMemberList] = useState([]); - - const {eventId} = useEventId(); - - useEffect(() => { - if (eventId === '') return; - - refreshStepList(); - - // TODO: (@weadie) useEffect를 꼭 써야하는가? - }, [eventId]); - - const refreshStepList = async () => { - const stepList = await requestStepList({eventId}); - - if (stepList.length !== 0) { - setNameMemberList(stepList[stepList.length - 1].members); - } - - setStepList(stepList); - }; - - const updateMemberList = async ({type, memberNameList}: {type: MemberType; memberNameList: string[]}) => { - try { - await requestUpdateMemberList({eventId, type, memberNameList}); - - // TODO: (@weadie) 클라이언트 단에서 멤버 목록을 관리하기 위한 로직. 개선이 필요하다. - if (type === 'IN') setNameMemberList(prev => [...prev, ...memberNameList]); - if (type === 'OUT') setNameMemberList(prev => prev.filter(name => !memberNameList.includes(name))); - - refreshStepList(); - } catch (error) { - alert(error); - } - }; - - const addBill = async (billList: Bill[]) => { - // TODO: (@weadie) 에러 처리 - await requestAddBillList({eventId, billList}); - - refreshStepList(); - }; - - const calculateBillSum = (actions: BillAction[]) => { - return actions.reduce((sum, {price}) => sum + price, 0); - }; - - const getTotalPrice = () => { - return stepList.reduce((sum, {type, actions}) => { - if (type === 'BILL') { - return sum + calculateBillSum(actions); - } - return sum; - }, 0); - }; - - return ( - - {children} - - ); -}; - -export const useStepList = () => { - const context = useContext(StepListContext); - - if (!context) { - throw new Error('useStepList는 StepListProvider 내에서 사용되어야 합니다.'); - } - return context; -}; - -export default StepListProvider; diff --git a/client/src/index.css b/client/src/index.css deleted file mode 100644 index 2f63176f6..000000000 --- a/client/src/index.css +++ /dev/null @@ -1,20 +0,0 @@ -body { - max-width: 768px; - height: 100lvh; - margin: 0 auto; - - overflow-y: scroll; - &::-webkit-scrollbar { - display: none; - } -} - -section { - width: 100%; -} - -#root { - display: flex; - flex-direction: column; - height: 100%; -} diff --git a/client/src/index.tsx b/client/src/index.tsx deleted file mode 100644 index b3d742c43..000000000 --- a/client/src/index.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import {RouterProvider} from 'react-router-dom'; - -import router from './router'; -import './reset.css'; -import './index.css'; - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -); diff --git a/client/src/mocks/memberReportSearchList.json b/client/src/mocks/memberReportSearchList.json deleted file mode 100644 index dfcb684b1..000000000 --- a/client/src/mocks/memberReportSearchList.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - {"name": "망쵸", "price": 1033200}, - {"name": "이상", "price": 10100}, - {"name": "소하", "price": 10000}, - {"name": "쿠키", "price": 100012}, - {"name": "토다리", "price": 1001230}, - {"name": "감자", "price": 1012300}, - {"name": "백호", "price": 10300}, - {"name": "웨디", "price": 1000} -] diff --git a/client/src/mocks/stepList.json b/client/src/mocks/stepList.json deleted file mode 100644 index cc3815a75..000000000 --- a/client/src/mocks/stepList.json +++ /dev/null @@ -1,86 +0,0 @@ -[ - { - "type": "IN", - "stepName": null, - "actions": [ - { - "actionId": 3, - "name": "망쵸", - "price": null, - "sequence": 3 - }, - { - "actionId": 4, - "name": "백호", - "price": null, - "sequence": 4 - } - ] - }, - { - "type": "BILL", - "stepName": "1차", - "actions": [ - { - "actionId": 1, - "name": "감자탕", - "price": 10000, - "sequence": 1 - }, - { - "actionId": 2, - "name": "인생네컷", - "price": 10000, - "sequence": 2 - } - ] - }, - { - "type": "IN", - "stepName": null, - "actions": [ - { - "actionId": 3, - "name": "망쵸", - "price": null, - "sequence": 3 - }, - { - "actionId": 4, - "name": "백호", - "price": null, - "sequence": 4 - } - ] - }, - { - "type": "OUT", - "stepName": null, - "actions": [ - { - "actionId": 5, - "name": "소하", - "price": null, - "sequence": 5 - }, - { - "actionId": 6, - "name": "웨디", - "price": null, - "sequence": 6 - } - ] - }, - { - "type": "BILL", - "stepName": "2차", - "actions": [ - { - "actionId": 8, - "name": "노래방", - "price": 20000, - "sequence": 7 - } - ] - } -] diff --git a/client/src/pages/Create/Complete.tsx b/client/src/pages/Create/Complete.tsx deleted file mode 100644 index 786979607..000000000 --- a/client/src/pages/Create/Complete.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import {useEffect, useState} from 'react'; -import {useLocation, useNavigate} from 'react-router-dom'; -import {FixedButton, MainLayout, Title, TopNav} from 'haengdong-design'; - -import {ROUTER_URLS} from '@constants/routerUrls'; - -const CompleteCreateEvent = () => { - const [url, setUrl] = useState(''); - const navigate = useNavigate(); - const location = useLocation(); - - useEffect(() => { - const getUrl = async () => { - // TODO: (@weadie) eventId를 location에서 불러오는 로직 함수로 분리해서 재사용 - const params = new URLSearchParams(location.search); - const eventId = params.get('eventId'); - - // TODO: (@weadie) eventId가 없는 경우에 대한 처리 필요 - setUrl(eventId ?? ''); - }; - - getUrl(); - }, []); - - return ( - - } /> - - <FixedButton onClick={() => navigate(`${ROUTER_URLS.event}/${url}/admin`)}>관리 페이지로 이동</FixedButton> - </MainLayout> - ); -}; - -export default CompleteCreateEvent; diff --git a/client/src/pages/Create/Name.tsx b/client/src/pages/Create/Name.tsx deleted file mode 100644 index c16870430..000000000 --- a/client/src/pages/Create/Name.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import {useState} from 'react'; -import {useNavigate} from 'react-router-dom'; -import {FixedButton, Input, MainLayout, Title, TopNav, Back} from 'haengdong-design'; - -import {requestCreateNewEvent} from '@apis/request/event'; - -import {ROUTER_URLS} from '@constants/routerUrls'; - -const CreateEvent = () => { - const [eventName, setEventName] = useState(''); - const navigate = useNavigate(); - - const submitEventName = async (event: React.FormEvent<HTMLFormElement>) => { - event.preventDefault(); - - const response = await requestCreateNewEvent({eventName}); - - if (response) { - const {eventId} = response; - navigate(`${ROUTER_URLS.eventCreateComplete}?${new URLSearchParams({eventId})}`); - } else { - // TODO: (@weadie) - alert('오류님'); - } - }; - - return ( - <MainLayout> - <TopNav> - <Back /> - </TopNav> - <Title title="행사 이름 입력" description="시작할 행사 이름을 입력해 주세요." /> - <form onSubmit={submitEventName} style={{padding: '0 1rem'}}> - <Input - value={eventName} - onChange={event => setEventName(event.target.value)} - onBlur={() => setEventName(eventName.trim())} - placeholder="ex) 행동대장 야유회" - /> - <FixedButton disabled={!eventName.length}>행동 개시!</FixedButton> - </form> - </MainLayout> - ); -}; - -export default CreateEvent; diff --git a/client/src/pages/Create/index.ts b/client/src/pages/Create/index.ts deleted file mode 100644 index 5ce37a93e..000000000 --- a/client/src/pages/Create/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export {default as CreateNamePage} from './Name'; -export {default as CreateCompletePage} from './Complete'; diff --git a/client/src/pages/Event/Admin/Admin.style.ts b/client/src/pages/Event/Admin/Admin.style.ts deleted file mode 100644 index 2025006d4..000000000 --- a/client/src/pages/Event/Admin/Admin.style.ts +++ /dev/null @@ -1,10 +0,0 @@ -import {css} from '@emotion/react'; - -export const ReceiptStyle = () => - css({ - display: 'flex', - flexDirection: 'column', - gap: '8px', - padding: '0 8px', - paddingBottom: '8.75rem', - }); diff --git a/client/src/pages/Event/Admin/Admin.tsx b/client/src/pages/Event/Admin/Admin.tsx deleted file mode 100644 index bda03da55..000000000 --- a/client/src/pages/Event/Admin/Admin.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import {useEffect, useState} from 'react'; -import {Title, FixedButton} from 'haengdong-design'; - -import StepList from '@components/StepList/StepList'; -import {useStepList} from '@hooks/useStepList/useStepList'; -import {requestGetEventName} from '@apis/request/event'; -import useEventId from '@hooks/useEventId/useEventId'; - -import {SetActionModalContent, SetInitialParticipants} from '@components/Modal'; - -import {ReceiptStyle} from './Admin.style'; - -export type PurchaseInformation = { - title: string; - price: number; -}; - -export type ParticipantType = { - name: string; - type: InOutType; -}; - -interface ModalRenderingProps { - memberNameList: string[]; - openBottomSheet: boolean; - setOrder: React.Dispatch<React.SetStateAction<number>>; - setOpenBottomSheet: React.Dispatch<React.SetStateAction<boolean>>; -} - -const ModalRendering = ({memberNameList, openBottomSheet, setOrder, setOpenBottomSheet}: ModalRenderingProps) => { - switch (memberNameList.length) { - case 0: - return <SetInitialParticipants setOpenBottomSheet={setOpenBottomSheet} openBottomSheet={openBottomSheet} />; - - default: - return ( - <SetActionModalContent - setOrder={setOrder} - setOpenBottomSheet={setOpenBottomSheet} - openBottomSheet={openBottomSheet} - /> - ); - } -}; - -const Admin = () => { - const [openBottomSheet, setOpenBottomSheet] = useState(false); - const [order, setOrder] = useState<number>(1); - - // TODO: (@weadie) eventName이 새로고침시 공간이 없다가 생겨나 레이아웃이 움직이는 문제 - const [eventName, setEventName] = useState(' '); - - const {getTotalPrice, memberNameList} = useStepList(); - - const {eventId} = useEventId(); - - // TODO: (@weadie) 아래 로직을 훅으로 분리합니다. - useEffect(() => { - if (eventId === '') return; - - const getEventName = async () => { - const {eventName} = await requestGetEventName({eventId: eventId ?? ''}); - - setEventName(eventName); - }; - - getEventName(); - }, [eventId]); - - return ( - <> - <Title - title={eventName} - description="“초기인원 설정하기” 버튼을 눌러서 행사 초기 인원을 설정해 주세요." - price={getTotalPrice()} - /> - <section css={ReceiptStyle}> - <StepList /> - {/* TODO: (@soha) 추후 버튼 width 화면에 맞게 수정 */} - <FixedButton - children={memberNameList.length === 0 ? '초기인원 설정하기' : '행동 추가하기'} - onClick={() => setOpenBottomSheet(prev => !prev)} - /> - {openBottomSheet && ( - <ModalRendering - memberNameList={memberNameList} - setOrder={setOrder} - setOpenBottomSheet={setOpenBottomSheet} - openBottomSheet={openBottomSheet} - /> - )} - </section> - </> - ); -}; - -export default Admin; diff --git a/client/src/pages/Event/Admin/index.ts b/client/src/pages/Event/Admin/index.ts deleted file mode 100644 index 9799a7485..000000000 --- a/client/src/pages/Event/Admin/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {default as AdminPage} from './Admin'; diff --git a/client/src/pages/Event/EventLayout.tsx b/client/src/pages/Event/EventLayout.tsx deleted file mode 100644 index 2b2b439de..000000000 --- a/client/src/pages/Event/EventLayout.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import {MainLayout, TopNav, Switch} from 'haengdong-design'; -import {Outlet} from 'react-router-dom'; - -import StepListProvider from '@hooks/useStepList/useStepList'; - -import useNavSwitch from '@hooks/useNavSwitch'; - -const EventLayout = () => { - const {nav, paths, onChange} = useNavSwitch(); - - return ( - <StepListProvider> - <MainLayout backgroundColor="gray"> - <TopNav> - <Switch value={nav} values={paths} onChange={onChange} /> - </TopNav> - <Outlet /> - </MainLayout> - </StepListProvider> - ); -}; - -export default EventLayout; diff --git a/client/src/pages/Event/Home/Home.tsx b/client/src/pages/Event/Home/Home.tsx deleted file mode 100644 index 8ff195cb8..000000000 --- a/client/src/pages/Event/Home/Home.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import {Tab, Tabs, Title} from 'haengdong-design'; -import {useEffect, useState} from 'react'; - -import MemberReportList from '@components/MemberReportList/MemberReportList'; -import StepList from '@components/StepList/StepList'; -import {useStepList} from '@hooks/useStepList/useStepList'; -import useEventId from '@hooks/useEventId/useEventId'; -import {requestGetEventName} from '@apis/request/event'; - -const HomeContent = () => { - const {getTotalPrice} = useStepList(); - const {eventId} = useEventId(); - - // TODO: (@soha) 행사 이름 나중에 따로 분리해야 함 - const [eventName, setEventName] = useState(' '); - - useEffect(() => { - if (eventId === '') return; - - const getEventName = async () => { - const {eventName} = await requestGetEventName({eventId: eventId ?? ''}); - - setEventName(eventName); - }; - - getEventName(); - }, [eventId]); - - return ( - <div> - <Title title={eventName} price={getTotalPrice()} /> - <Tabs tabsContainerStyle={{gap: '1rem'}}> - <Tab label="전체 지출 내역" content={<StepList />} /> - <Tab label="참여자 별 내역" content={<MemberReportList />} /> - </Tabs> - </div> - ); -}; - -export default HomeContent; diff --git a/client/src/pages/Event/Home/index.ts b/client/src/pages/Event/Home/index.ts deleted file mode 100644 index 75e27b8a3..000000000 --- a/client/src/pages/Event/Home/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {default as HomePage} from './Home'; diff --git a/client/src/pages/Event/index.ts b/client/src/pages/Event/index.ts deleted file mode 100644 index af2aa805d..000000000 --- a/client/src/pages/Event/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {default as EventPage} from './EventLayout'; diff --git a/client/src/pages/Main/Main.tsx b/client/src/pages/Main/Main.tsx deleted file mode 100644 index 2a032b5cf..000000000 --- a/client/src/pages/Main/Main.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import {useNavigate} from 'react-router-dom'; -import {FixedButton, MainLayout, Title, TopNav} from 'haengdong-design'; - -import {ROUTER_URLS} from '@constants/routerUrls'; - -const Main = () => { - const navigate = useNavigate(); - - return ( - <MainLayout> - {/* <TopNav navType="back" /> */} - <Title title="행동대장" description="랜딩페이지입니다. 뿌뿌 잠깐만 테스트해볼게요.." /> - <TopNav children={<></>} /> - <Title title="행동대장" description="랜딩페이지입니다." /> - <FixedButton onClick={() => navigate(ROUTER_URLS.eventCreateName)}>행사 생성하기</FixedButton> - </MainLayout> - ); -}; - -export default Main; diff --git a/client/src/pages/Main/index.ts b/client/src/pages/Main/index.ts deleted file mode 100644 index c3cce532e..000000000 --- a/client/src/pages/Main/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {default as MainPage} from './Main'; diff --git a/client/src/reset.css b/client/src/reset.css deleted file mode 100644 index 1a7ea162d..000000000 --- a/client/src/reset.css +++ /dev/null @@ -1,136 +0,0 @@ -/* http://meyerweb.com/eric/tools/css/reset/ - v2.0 | 20110126 - License: none (public domain) -*/ - -html, -body, -div, -span, -applet, -object, -iframe, -h1, -h2, -h3, -h4, -h5, -h6, -p, -blockquote, -pre, -a, -abbr, -acronym, -address, -big, -cite, -code, -del, -dfn, -em, -img, -ins, -kbd, -q, -s, -samp, -small, -strike, -strong, -sub, -sup, -tt, -b, -u, -i, -center, -dl, -dt, -dd, -ol, -ul, -li, -fieldset, -form, -label, -legend, -table, -caption, -tbody, -tfoot, -thead, -tr, -th, -td, -article, -aside, -canvas, -details, -embed, -figure, -figcaption, -footer, -header, -hgroup, -menu, -nav, -output, -ruby, -section, -summary, -time, -mark, -audio, -video { - vertical-align: baseline; - margin: 0; - border: 0; - padding: 0; - font-size: 100%; - font: inherit; -} -/* HTML5 display-role reset for older browsers */ -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -menu, -nav, -section { - display: block; -} -body { - line-height: 1; -} -ol, -ul { - list-style: none; -} -blockquote, -q { - quotes: none; -} -blockquote:before, -blockquote:after, -q:before, -q:after { - content: ''; - content: none; -} -table { - border-collapse: collapse; - border-spacing: 0; -} -button { - cursor: pointer; - border: none; - background-color: transparent; -} -* { - box-sizing: border-box; -} diff --git a/client/src/router.tsx b/client/src/router.tsx deleted file mode 100644 index 70f7a1e71..000000000 --- a/client/src/router.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import {createBrowserRouter} from 'react-router-dom'; - -import {AdminPage} from '@pages/Event/Admin'; -import {HomePage} from '@pages/Event/Home'; - -import {MainPage} from '@pages/Main'; -import {CreateNamePage, CreateCompletePage} from '@pages/Create'; -import {EventPage} from '@pages/Event'; - -import {ROUTER_URLS} from '@constants/routerUrls'; - -import App from './App'; - -const router = createBrowserRouter([ - { - path: '', - element: <App />, - children: [ - { - index: true, - path: ROUTER_URLS.main, - element: <MainPage />, - }, - { - path: ROUTER_URLS.eventCreateName, - element: <CreateNamePage />, - }, - { - path: ROUTER_URLS.eventCreateComplete, - element: <CreateCompletePage />, - }, - { - path: ROUTER_URLS.event, - element: <EventPage />, - children: [ - {path: ROUTER_URLS.eventManage, element: <AdminPage />}, - {path: ROUTER_URLS.home, element: <HomePage />}, - ], - }, - ], - }, -]); - -export default router; diff --git a/client/src/type.d.ts b/client/src/type.d.ts deleted file mode 100644 index a81318e4c..000000000 --- a/client/src/type.d.ts +++ /dev/null @@ -1,18 +0,0 @@ -type MemberType = 'IN' | 'OUT'; - -type InOutType = '늦참' | '탈주'; - -type MemberReport = { - name: string; - price: number; -}; - -type Bill = { - title: string; - price: number; -}; - -// TODO: (@weadie) 준 데이터 형식에서 steps를 빼내 flat하게 사용중. 일관성있게 하는게 좋긴 하나 사용시 번거로움이 있을 거라고 판단. -type StepList = { - steps: (MemberStep | BillStep)[]; -}; diff --git a/client/tsconfig.json b/client/tsconfig.json deleted file mode 100644 index b049bf464..000000000 --- a/client/tsconfig.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "compilerOptions": { - "sourceMap": true, - "module": "ES2020", - "target": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "useDefineForClassFields": true, - "removeComments": true, - "skipLibCheck": true, - - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - - "jsx": "react-jsx", - "strict": true, - // "noUnusedLocals": true, - // "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true, - - "types": ["node", "jest"], - "esModuleInterop": true, - "strictNullChecks": true, - "strictFunctionTypes": true, - "strictBindCallApply": true, - "strictPropertyInitialization": true, - "noImplicitAny": true, - "noImplicitThis": true, - "alwaysStrict": true, - "noImplicitReturns": true, - "forceConsistentCasingInFileNames": true, - "jsxImportSource": "@emotion/react", - - "baseUrl": "./src", - "paths": { - "@apis/*": ["apis/*"], - "@assets/*": ["assets/*"], - "@components/*": ["components/*"], - "@constants/*": ["constants/*"], - "@hooks/*": ["hooks/*"], - "@mocks/*": ["mocks/*"], - "@pages/*": ["pages/*"], - "@utils/*": ["utils/*"] - }, - "outDir": "./dist" - }, - "node": true, - "include": ["src"] -} diff --git a/client/webpack.config.js b/client/webpack.config.js deleted file mode 100644 index 9545ecf2f..000000000 --- a/client/webpack.config.js +++ /dev/null @@ -1,75 +0,0 @@ -import path from 'path'; -import HtmlWebpackPlugin from 'html-webpack-plugin'; -import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; -import {ModifySourcePlugin, ConcatOperation} from 'modify-source-webpack-plugin'; -import {fileURLToPath} from 'url'; -import Dotenv from 'dotenv-webpack'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -// dotenv.config({path: path.join(__dirname, '.env')}); - -export default { - mode: 'development', - entry: './src/index.tsx', - resolve: { - extensions: ['.js', '.jsx', '.ts', '.tsx'], - alias: { - '@apis': path.resolve(__dirname, 'src/apis/'), - '@assets': path.resolve(__dirname, 'src/assets/'), - '@components': path.resolve(__dirname, 'src/components/'), - '@constants': path.resolve(__dirname, 'src/constants/'), - '@hooks': path.resolve(__dirname, 'src/hooks/'), - '@mocks': path.resolve(__dirname, 'src/mocks/'), - '@pages': path.resolve(__dirname, 'src/pages/'), - '@utils': path.resolve(__dirname, 'src/utils/'), - }, - }, - output: { - path: path.join(__dirname, 'dist'), - filename: 'bundle.min.js', - publicPath: '/', - }, - module: { - rules: [ - { - test: /\.tsx?$/, - loader: 'ts-loader', - exclude: /node_modules/, - }, - { - test: /\.css$/i, - use: ['style-loader', 'css-loader'], - }, - { - test: /\.svg$/, - use: [ - { - loader: '@svgr/webpack', - }, - ], - }, - ], - }, - plugins: [ - new HtmlWebpackPlugin({ - template: './index.html', - }), - new ForkTsCheckerWebpackPlugin(), - new ModifySourcePlugin({ - rules: [ - { - test: /\.tsx$/i, - operations: [new ConcatOperation('start', '/** @jsxImportSource @emotion/react */\n\n')], - }, - ], - }), - new Dotenv(), - ], - devServer: { - port: 3000, - hot: true, - historyApiFallback: true, - }, -}; From fb3acc5129c5484d84c7da7e6a129e59678bca69 Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Tue, 30 Jul 2024 16:47:53 +0900 Subject: [PATCH 106/178] =?UTF-8?q?refactor:=20CD=20workflow=20main,=20dev?= =?UTF-8?q?elop=20=EB=B6=84=EB=A6=AC=20(#163)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: CD workflow main, develop 분리 및 dockerfile 수정 * refactor: trigger test 브랜치 추가 * refactor: feature/#147 에 push test * refactor: github actions self-hosted runner tag 추가 * refactor: feature/#147 runner 구분 테스트 * refactor: feature/#147 prod runner 구분 테스트 * refactor: feature/#147 prod runner 구분 테스트2 * refactor: feature/#147 prod runner 구분 테스트3 * refactor: feature/#147 prod runner 구분 테스트3 * refactor: prod, dev yml 분리 완료 및 서버 테스트 완료 --- .../{backend-push.yml => backend-dev.yml} | 10 +-- .github/workflows/backend-prod.yml | 74 +++++++++++++++++++ .github/workflows/backend-pull-request.yml | 2 +- .gitmodules | 1 + server/Dockerfile | 2 +- server/src/main/resources/application.yml | 9 +++ server/src/main/resources/config | 1 + 7 files changed, 92 insertions(+), 7 deletions(-) rename .github/workflows/{backend-push.yml => backend-dev.yml} (78%) create mode 100644 .github/workflows/backend-prod.yml create mode 160000 server/src/main/resources/config diff --git a/.github/workflows/backend-push.yml b/.github/workflows/backend-dev.yml similarity index 78% rename from .github/workflows/backend-push.yml rename to .github/workflows/backend-dev.yml index c9c2316c8..9e56c7615 100644 --- a/.github/workflows/backend-push.yml +++ b/.github/workflows/backend-dev.yml @@ -2,7 +2,7 @@ name: backend-push on: push: - branches: [ "main", "develop" ] + branches: [ "be-dev" ] paths: - 'server/**' @@ -52,11 +52,11 @@ jobs: - name: Build and push run: | docker buildx build --platform linux/arm64 -t \ - ${{ secrets.DOCKER_USERNAME }}/haengdong-backend-dev --push . + ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }} --push . deploy: needs: build - runs-on: self-hosted + runs-on: [ self-hosted, backend-dev ] steps: - name: Docker remove run: | @@ -68,7 +68,7 @@ jobs: fi - name: Docker Image pull - run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/haengdong-backend-dev + run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }} - name: Docker run - run: sudo docker run -d -p 8080:8080 --name haengdong-backend-dev ${{ secrets.DOCKER_USERNAME }}/haengdong-backend-dev + run: sudo docker run -d -p 8080:8080 -e SPRING_PROFILES_ACTIVE=dev --name haengdong-backend ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }} diff --git a/.github/workflows/backend-prod.yml b/.github/workflows/backend-prod.yml new file mode 100644 index 000000000..ffc0b771a --- /dev/null +++ b/.github/workflows/backend-prod.yml @@ -0,0 +1,74 @@ +name: backend-push + +on: + push: + branches: [ "main" ] + paths: + - 'server/**' + +jobs: + build: + runs-on: ubuntu-latest + + defaults: + run: + shell: bash + working-directory: ./server + + permissions: + contents: read + + steps: + - name: CheckOut + uses: actions/checkout@v4 + with: + token: ${{secrets.CONFIG_SUBMODULE_TOKEN}} + submodules: true + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Test with Gradle Wrapper + run: ./gradlew clean build + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Set up Docker BuildX + uses: docker/setup-buildx-action@v3 + + - name: Build and push + run: | + docker buildx build --platform linux/arm64 -t \ + ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }} --push . + + deploy: + needs: build + runs-on: [ self-hosted, backend-prod ] + steps: + - name: Docker remove + run: | + CONTAINER_IDS=$(sudo docker ps -qa) + if [ -n "$CONTAINER_IDS" ]; then + sudo docker rm -f $CONTAINER_IDS + else + echo "No running containers found." + fi + + - name: Docker Image pull + run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }} + + - name: Docker run + run: sudo docker run -d -p 8080:8080 -e SPRING_PROFILES_ACTIVE=prod --name haengdong-backend ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }} diff --git a/.github/workflows/backend-pull-request.yml b/.github/workflows/backend-pull-request.yml index 6ede1b600..797f88326 100644 --- a/.github/workflows/backend-pull-request.yml +++ b/.github/workflows/backend-pull-request.yml @@ -2,7 +2,7 @@ name: backend-pull-request on: pull_request: - branches: [ "main", "develop" ] + branches: [ "main", "be-dev" ] paths: - 'server/**' diff --git a/.gitmodules b/.gitmodules index a067fc391..d013a93bc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,4 @@ [submodule "server/src/main/resources/config"] + branch = main path = server/src/main/resources/config url = https://github.com/woowacourse-teams/2024-haeng-dong-config.git diff --git a/server/Dockerfile b/server/Dockerfile index 37e37d237..ae8c9c880 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -6,4 +6,4 @@ COPY /build/libs/*.jar /app/haengdong-0.0.1-SNAPSHOT.jar EXPOSE 8080 ENTRYPOINT ["java"] -CMD ["-Dspring.profiles.active=dev", "-jar", "haengdong-0.0.1-SNAPSHOT.jar"] +CMD ["-Dspring.profiles.active=${SPRING_PROFILES_ACTIVE}", "-jar", "haengdong-0.0.1-SNAPSHOT.jar"] diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index faf7a36f1..17d01950e 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -24,8 +24,17 @@ cors: --- +spring: + config: + import: classpath:config/application-prod.yml + activate: + on-profile: prod + +--- + spring: config: import: classpath:config/application-dev.yml activate: on-profile: dev + diff --git a/server/src/main/resources/config b/server/src/main/resources/config new file mode 160000 index 000000000..c946d00b8 --- /dev/null +++ b/server/src/main/resources/config @@ -0,0 +1 @@ +Subproject commit c946d00b8f35ee39446f780cc2cf3983461cd38c From fda3f0dd1b784b94afa5ad77ec881e4002c05490 Mon Sep 17 00:00:00 2001 From: JUHA <84626225+khabh@users.noreply.github.com> Date: Wed, 31 Jul 2024 17:39:45 +0900 Subject: [PATCH 107/178] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=20=EB=AA=A8?= =?UTF-8?q?=EB=8B=88=ED=84=B0=EB=A7=81=20=ED=99=98=EA=B2=BD=20=EA=B5=AC?= =?UTF-8?q?=EC=B6=95=20(#169)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/build.gradle | 1 + server/src/main/resources/application.yml | 17 +++++++++++++++++ server/src/main/resources/logback-spring.xml | 19 +++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 server/src/main/resources/logback-spring.xml diff --git a/server/build.gradle b/server/build.gradle index 26f6ec262..526c3640e 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -27,6 +27,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'org.springframework.boot:spring-boot-starter-actuator' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' runtimeOnly 'com.mysql:mysql-connector-j' diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index 17d01950e..c0099e93e 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -22,6 +22,23 @@ cors: max-age: 3600 allowed-origins: http://localhost:3000, https://haengdong.pro, https://dev.haengdong.pro, https://app.haengdong.pro +management: + endpoints: + web: + exposure: + include: logfile + +logging: + level: + root: info + org.springframework.web: debug + server.haengdong: debug + + file: + name: logs/spring-boot-application.log + path: logs + config: classpath:logback-spring.xml + --- spring: diff --git a/server/src/main/resources/logback-spring.xml b/server/src/main/resources/logback-spring.xml new file mode 100644 index 000000000..204130e8c --- /dev/null +++ b/server/src/main/resources/logback-spring.xml @@ -0,0 +1,19 @@ +<configuration> + <appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>logs/spring-boot-application.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>logs/spring-boot-application.%d{yyyy-MM-dd}.log</fileNamePattern> + <maxHistory>30</maxHistory> + </rollingPolicy> + <encoder> + <pattern>%d{yyyy-MM-dd HH:mm:ss} - %msg%n</pattern> + </encoder> + </appender> + + <root level="INFO"> + <appender-ref ref="ROLLING"/> + </root> + + <logger name="org.springframework.web" level="DEBUG"/> + <logger name="server.haengdong" level="DEBUG"/> +</configuration> From 0739181ba5b2e886f3c7e1fab96b3a673cf4429b Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Thu, 1 Aug 2024 10:14:47 +0900 Subject: [PATCH 108/178] =?UTF-8?q?feat:=20=EC=98=88=EC=99=B8=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20=EA=B5=AC=EC=B2=B4=ED=99=94=20(#161)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 예외 핸들링 추가 * refactor: 예외 메시지 구체화 및 검증 역할 변경 * feat: 에러 코드 추가 * style: 개행 제거 * refactor: 멤버 액션 예외 ErrorCode 분리 * feat: 로깅 추가 --- .../application/MemberActionFactory.java | 35 +++--------- .../application/MemberActionService.java | 3 +- .../domain/action/CurrentMembers.java | 13 ++++- .../haengdong/exception/ErrorResponse.java | 9 ++- .../exception/GlobalExceptionHandler.java | 24 +++++--- .../exception/HaengdongErrorCode.java | 22 ++++---- .../exception/HaengdongException.java | 5 -- .../application/MemberActionFactoryTest.java | 55 +++++++++++++------ .../domain/action/CurrentMembersTest.java | 40 ++++++++++++++ 9 files changed, 134 insertions(+), 72 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/MemberActionFactory.java b/server/src/main/java/server/haengdong/application/MemberActionFactory.java index cbe34f0ef..9d9afb6ac 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionFactory.java +++ b/server/src/main/java/server/haengdong/application/MemberActionFactory.java @@ -8,6 +8,7 @@ import server.haengdong.application.request.MemberActionSaveAppRequest; import server.haengdong.application.request.MemberActionsSaveAppRequest; import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.CurrentMembers; import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionStatus; import server.haengdong.domain.action.MemberGroupIdProvider; @@ -22,11 +23,11 @@ public class MemberActionFactory { public List<MemberAction> createMemberActions( MemberActionsSaveAppRequest request, - List<MemberAction> memberActions, + CurrentMembers currentMembers, Action action ) { validateMemberNames(request); - validateActions(request, memberActions); + validateActions(request, currentMembers); Long memberGroupId = memberGroupIdProvider.createGroupId(); List<MemberAction> createdMemberActions = new ArrayList<>(); @@ -51,32 +52,12 @@ private void validateMemberNames(MemberActionsSaveAppRequest request) { } } - private void validateActions(MemberActionsSaveAppRequest request, List<MemberAction> memberActions) { - List<MemberAction> reverseSortedMemberActions = memberActions.stream() - .sorted(Comparator.comparing(MemberAction::getSequence).reversed()) - .toList(); - - for (MemberActionSaveAppRequest action : request.actions()) { - validateAction(action, reverseSortedMemberActions); - } - } + private void validateActions(MemberActionsSaveAppRequest request, CurrentMembers currentMembers) { + List<MemberActionSaveAppRequest> actions = request.actions(); - private void validateAction(MemberActionSaveAppRequest request, List<MemberAction> memberActions) { - MemberActionStatus memberActionStatus = MemberActionStatus.of(request.status()); - if (isInvalidStatus(memberActions, request.name(), memberActionStatus)) { - throw new HaengdongException(HaengdongErrorCode.INVALID_MEMBER_ACTION); + for (MemberActionSaveAppRequest action : actions) { + MemberActionStatus memberActionStatus = MemberActionStatus.of(action.status()); + currentMembers.validate(action.name(), memberActionStatus); } } - - private boolean isInvalidStatus( - List<MemberAction> memberActions, - String memberName, - MemberActionStatus memberActionStatus - ) { - return memberActions.stream() - .filter(action -> action.isSameName(memberName)) - .findFirst() - .map(action -> action.isSameStatus(memberActionStatus)) - .orElse(MemberActionStatus.IN != memberActionStatus); - } } diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java index 5094bf2c0..f893bd08d 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionService.java +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -31,8 +31,9 @@ public void saveMemberAction(String token, MemberActionsSaveAppRequest request) Event event = findEvent(token); List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event); + CurrentMembers currentMembers = CurrentMembers.of(findMemberActions); Action action = createStartAction(event); - List<MemberAction> memberActions = memberActionFactory.createMemberActions(request, findMemberActions, action); + List<MemberAction> memberActions = memberActionFactory.createMemberActions(request, currentMembers, action); memberActionRepository.saveAll(memberActions); } diff --git a/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java b/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java index 298a8a965..082b9139d 100644 --- a/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java +++ b/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java @@ -5,6 +5,8 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; public class CurrentMembers { @@ -14,7 +16,7 @@ public CurrentMembers() { this(new HashSet<>()); } - private CurrentMembers(Set<String> members) { + protected CurrentMembers(Set<String> members) { this.members = members; } @@ -52,6 +54,15 @@ public CurrentMembers addMemberAction(MemberAction memberAction) { return new CurrentMembers(currentMembers); } + public void validate(String memberName, MemberActionStatus memberActionStatus) { + if (memberActionStatus == MemberActionStatus.IN && members.contains(memberName)) { + throw new HaengdongException(HaengdongErrorCode.INVALID_MEMBER_IN_ACTION); + } + if (memberActionStatus == MemberActionStatus.OUT && !members.contains(memberName)) { + throw new HaengdongException(HaengdongErrorCode.INVALID_MEMBER_OUT_ACTION); + } + } + public boolean isEmpty() { return members.isEmpty(); } diff --git a/server/src/main/java/server/haengdong/exception/ErrorResponse.java b/server/src/main/java/server/haengdong/exception/ErrorResponse.java index c797b811a..69133a66c 100644 --- a/server/src/main/java/server/haengdong/exception/ErrorResponse.java +++ b/server/src/main/java/server/haengdong/exception/ErrorResponse.java @@ -1,10 +1,15 @@ package server.haengdong.exception; public record ErrorResponse( + String code, String message ) { - public static ErrorResponse of(String message) { - return new ErrorResponse(message); + public static ErrorResponse of(HaengdongErrorCode errorCode) { + return new ErrorResponse(errorCode.getCode(), errorCode.getMessage()); + } + + public static ErrorResponse of(HaengdongErrorCode errorCode, String message){ + return new ErrorResponse(errorCode.getCode(), message); } } diff --git a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java index bb3138cc7..fb15afc56 100644 --- a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java +++ b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java @@ -3,41 +3,51 @@ import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.resource.NoResourceFoundException; @Slf4j @RestControllerAdvice public class GlobalExceptionHandler { - @ExceptionHandler(HttpRequestMethodNotSupportedException.class) - public ResponseEntity<ErrorResponse> haengdongException() { + @ExceptionHandler({HttpRequestMethodNotSupportedException.class, NoResourceFoundException.class}) + public ResponseEntity<ErrorResponse> noResourceException() { return ResponseEntity.badRequest() - .body(ErrorResponse.of(HaengdongErrorCode.BAD_REQUEST.getMessage())); + .body(ErrorResponse.of(HaengdongErrorCode.NO_RESOURCE_REQUEST)); + } + + @ExceptionHandler(HttpMessageNotReadableException.class) + public ResponseEntity<ErrorResponse> httpMessageNotReadableException() { + return ResponseEntity.badRequest() + .body(ErrorResponse.of(HaengdongErrorCode.MESSAGE_NOT_READABLE)); } @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<ErrorResponse> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { + log.info(e.getMessage(), e); String errorMessage = e.getFieldErrors().stream() .map(error -> error.getField() + " " + error.getDefaultMessage()) .collect(Collectors.joining(", ")); return ResponseEntity.badRequest() - .body(ErrorResponse.of(errorMessage)); + .body(ErrorResponse.of(HaengdongErrorCode.BAD_REQUEST, errorMessage)); } @ExceptionHandler(HaengdongException.class) public ResponseEntity<ErrorResponse> haengdongException(HaengdongException e) { - return ResponseEntity.status(e.getStatusCode()) - .body(ErrorResponse.of(e.getMessage())); + log.info(e.getMessage(), e); + return ResponseEntity.badRequest() + .body(ErrorResponse.of(e.getErrorCode())); } @ExceptionHandler(Exception.class) public ResponseEntity<ErrorResponse> handleException(Exception e) { log.error(e.getMessage(), e); return ResponseEntity.internalServerError() - .body(ErrorResponse.of(HaengdongErrorCode.INTERNAL_SERVER_ERROR.getMessage())); + .body(ErrorResponse.of(HaengdongErrorCode.INTERNAL_SERVER_ERROR)); } } diff --git a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java index 792baa838..052b97fe2 100644 --- a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java +++ b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java @@ -1,24 +1,24 @@ package server.haengdong.exception; import lombok.Getter; -import org.springframework.http.HttpStatus; @Getter public enum HaengdongErrorCode { - BAD_REQUEST(HttpStatus.BAD_REQUEST, "잘못된 요청입니다."), - DUPLICATED_MEMBER_ACTION(HttpStatus.BAD_REQUEST, "올바르지 않은 인원 요청입니다."), - INVALID_MEMBER_ACTION(HttpStatus.BAD_REQUEST, "잘못된 맴버 액션입니다."), - - NOT_FOUND_EVENT(HttpStatus.NOT_FOUND, "존재하지 않는 행사입니다."), - - INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버 내부에서 에러가 발생했습니다."), + BAD_REQUEST("R_001", "잘못된 요청입니다."), + NO_RESOURCE_REQUEST("R_002", "잘못된 엔드포인트입니다."), + MESSAGE_NOT_READABLE("R_003", "읽을 수 없는 요청 형식입니다."), + DUPLICATED_MEMBER_ACTION("MA_001", "중복된 인원이 존재합니다."), + INVALID_MEMBER_IN_ACTION("MA_002", "현재 참여하고 있는 인원이 존재합니다."), + INVALID_MEMBER_OUT_ACTION("MA_003", "현재 참여하고 있지 않는 인원이 존재합니다."), + NOT_FOUND_EVENT("EV_400", "존재하지 않는 행사입니다."), + INTERNAL_SERVER_ERROR("S_001", "서버 내부에서 에러가 발생했습니다."), ; - private final HttpStatus httpStatus; + private final String code; private final String message; - HaengdongErrorCode(HttpStatus httpStatus, String message) { - this.httpStatus = httpStatus; + HaengdongErrorCode(String code, String message) { + this.code = code; this.message = message; } } diff --git a/server/src/main/java/server/haengdong/exception/HaengdongException.java b/server/src/main/java/server/haengdong/exception/HaengdongException.java index 812df50f8..d418a2feb 100644 --- a/server/src/main/java/server/haengdong/exception/HaengdongException.java +++ b/server/src/main/java/server/haengdong/exception/HaengdongException.java @@ -1,7 +1,6 @@ package server.haengdong.exception; import lombok.Getter; -import org.springframework.http.HttpStatusCode; @Getter public class HaengdongException extends RuntimeException { @@ -18,10 +17,6 @@ public HaengdongException(HaengdongErrorCode errorCode, String message) { this.message = message; } - public HttpStatusCode getStatusCode() { - return errorCode.getHttpStatus(); - } - @Override public String getMessage() { if (message == null) { diff --git a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java index 40bee2ff6..278423759 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java @@ -14,6 +14,7 @@ import server.haengdong.application.request.MemberActionSaveAppRequest; import server.haengdong.application.request.MemberActionsSaveAppRequest; import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.CurrentMembers; import server.haengdong.domain.event.Event; import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionStatus; @@ -56,10 +57,12 @@ void createMemberActionsTest() { MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); + List<MemberAction> unorderedMemberActions = List.of(memberAction2, memberAction1); + CurrentMembers currentMembers = CurrentMembers.of(unorderedMemberActions); Action startAction = new Action(event, 3L); - assertThatThrownBy(() -> memberActionFactory.createMemberActions(request, unorderedMemberActions, startAction)) + assertThatThrownBy(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) .isInstanceOf(HaengdongException.class); } @@ -75,8 +78,10 @@ void createMemberActionsTest1() { List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); List<MemberAction> memberActions = memberActionFactory.createMemberActions(memberActionsSaveAppRequest, - List.of(memberAction), startAction); + currentMembers, startAction + ); assertThat(memberActions).hasSize(1) .extracting(MemberAction::getAction, MemberAction::getMemberName, MemberAction::getStatus) @@ -96,8 +101,9 @@ void createMemberActionsTest2() { MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); - assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) .doesNotThrowAnyException(); } @@ -115,10 +121,9 @@ void createMemberActionsTest3() { MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( List.of(new MemberActionSaveAppRequest("토다리", "IN"))); Action startAction = new Action(event, 3L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction1, memberAction2)); - assertThatCode( - () -> memberActionFactory.createMemberActions(request, List.of(memberAction1, memberAction2), - startAction)) + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) .doesNotThrowAnyException(); } @@ -133,8 +138,9 @@ void createMemberActionsTest4() { MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); - assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) .doesNotThrowAnyException(); } @@ -146,8 +152,10 @@ void createMemberActionTest5() { MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( List.of(new MemberActionSaveAppRequest("쿠키", "OUT"))); Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of()); - assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(), startAction)) + assertThatCode( + () -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) .isInstanceOf(HaengdongException.class); } @@ -162,8 +170,9 @@ void createMemberActionTest6() { MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); - assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) .isInstanceOf(HaengdongException.class); } @@ -173,11 +182,15 @@ void createMemberActionTest7() { Event event = eventRepository.save(new Event("test", "TOKEN")); MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("쿠키", "IN"), - new MemberActionSaveAppRequest("쿠키", "IN"))); + List.of( + new MemberActionSaveAppRequest("쿠키", "IN"), + new MemberActionSaveAppRequest("쿠키", "IN") + )); Action startAction = new Action(event, 1L); + CurrentMembers currentMembers = CurrentMembers.of(List.of()); - assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(), startAction)) + assertThatCode( + () -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) .isInstanceOf(HaengdongException.class); } @@ -190,11 +203,14 @@ void createMemberActionTest8() { memberActionRepository.save(memberAction); MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("쿠키", "OUT"), - new MemberActionSaveAppRequest("쿠키", "OUT"))); + List.of( + new MemberActionSaveAppRequest("쿠키", "OUT"), + new MemberActionSaveAppRequest("쿠키", "OUT") + )); Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); - assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) .isInstanceOf(HaengdongException.class); } @@ -207,11 +223,14 @@ void createMemberActionTest9() { memberActionRepository.save(memberAction); MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("쿠키", "IN"), - new MemberActionSaveAppRequest("쿠키", "OUT"))); + List.of( + new MemberActionSaveAppRequest("쿠키", "IN"), + new MemberActionSaveAppRequest("쿠키", "OUT") + )); Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); - assertThatCode(() -> memberActionFactory.createMemberActions(request, List.of(memberAction), startAction)) + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) .isInstanceOf(HaengdongException.class); } } diff --git a/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java b/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java index 389ca70c1..3ed02ddc5 100644 --- a/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java +++ b/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java @@ -1,6 +1,7 @@ package server.haengdong.domain.action; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; import static server.haengdong.domain.action.MemberActionStatus.IN; import static server.haengdong.domain.action.MemberActionStatus.OUT; @@ -8,7 +9,10 @@ import java.util.Set; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; import server.haengdong.domain.event.Event; +import server.haengdong.exception.HaengdongException; class CurrentMembersTest { @@ -55,4 +59,40 @@ void addMemberAction2() { assertThat(addedCurrentMembers.getMembers()).hasSize(0); } + + @DisplayName("현재 참여중인 인원은 나갈 수 있다.") + @Test + void validate1() { + CurrentMembers currentMembers = new CurrentMembers(Set.of("토다리")); + + assertThatCode(() -> currentMembers.validate("토다리", OUT)) + .doesNotThrowAnyException(); + } + + @DisplayName("현재 참여중이지 않은 인원은 들어올 수 있다.") + @Test + void validate2() { + CurrentMembers currentMembers = new CurrentMembers(Set.of("쿠키")); + + assertThatCode(() -> currentMembers.validate("토다리", IN)) + .doesNotThrowAnyException(); + } + + @DisplayName("현재 참여중인 인원은 들어올 수 없다.") + @Test + void validate3() { + CurrentMembers currentMembers = new CurrentMembers(Set.of("토다리")); + + assertThatCode(() -> currentMembers.validate("토다리", IN)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("현재 참여중이지 않은 인원은 나갈 수 없다.") + @Test + void validate4() { + CurrentMembers currentMembers = new CurrentMembers(Set.of("쿠키")); + + assertThatCode(() -> currentMembers.validate("토다리", OUT)) + .isInstanceOf(HaengdongException.class); + } } From d381d9dfad70ff374d806ae59e800b2bb5c07607 Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Sun, 4 Aug 2024 14:16:01 +0900 Subject: [PATCH 109/178] =?UTF-8?q?refactor:=20=EC=95=A1=EC=85=98=20?= =?UTF-8?q?=EC=9D=B4=EB=A0=A5=20=EC=A1=B0=ED=9A=8C=20=EB=A6=AC=ED=8E=99?= =?UTF-8?q?=ED=86=A0=EB=A7=81=20(#141)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/EventController.java | 8 +-- .../response/ActionsResponse.java | 28 --------- .../presentation/response/StepResponse.java | 58 ++++------------- .../presentation/response/StepsResponse.java | 52 +++++++++++++++ .../response/StepResponseTest.java | 57 ----------------- .../response/StepsResponseTest.java | 63 +++++++++++++++++++ 6 files changed, 132 insertions(+), 134 deletions(-) delete mode 100644 server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/StepsResponse.java delete mode 100644 server/src/test/java/server/haengdong/presentation/response/StepResponseTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java index 9fbe098ce..816e7ed26 100644 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -12,7 +12,7 @@ import server.haengdong.presentation.request.EventSaveRequest; import server.haengdong.presentation.response.EventDetailResponse; import server.haengdong.presentation.response.EventResponse; -import server.haengdong.presentation.response.StepResponse; +import server.haengdong.presentation.response.StepsResponse; @RequiredArgsConstructor @RestController @@ -35,9 +35,9 @@ public ResponseEntity<EventDetailResponse> findEvent(@PathVariable("eventId") St } @GetMapping("/api/events/{eventId}/actions") - public ResponseEntity<StepResponse> findActions(@PathVariable("eventId") String token) { - StepResponse stepResponse = StepResponse.of(eventService.findActions(token)); + public ResponseEntity<StepsResponse> findActions(@PathVariable("eventId") String token) { + StepsResponse stepsResponse = StepsResponse.of(eventService.findActions(token)); - return ResponseEntity.ok(stepResponse); + return ResponseEntity.ok(stepsResponse); } } diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java b/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java deleted file mode 100644 index 188c48dc9..000000000 --- a/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java +++ /dev/null @@ -1,28 +0,0 @@ -package server.haengdong.presentation.response; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import server.haengdong.application.response.ActionAppResponse; - -public record ActionsResponse( - String type, - String stepName, - Set<String> members, - List<ActionResponse> actions -) { - - public static ActionsResponse of(List<ActionAppResponse> actions, Set<String> members) { - List<ActionResponse> actionResponses = actions.stream() - .map(ActionResponse::of) - .toList(); - - String actionType = actions.get(0).actionTypeName(); - return new ActionsResponse( - actionType, - null, - new HashSet<>(members), - actionResponses - ); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/response/StepResponse.java b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java index a8f3877ef..c3e854f4e 100644 --- a/server/src/main/java/server/haengdong/presentation/response/StepResponse.java +++ b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java @@ -1,57 +1,25 @@ package server.haengdong.presentation.response; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; -import java.util.Set; import server.haengdong.application.response.ActionAppResponse; public record StepResponse( - List<ActionsResponse> steps + String type, + List<String> members, + List<ActionResponse> actions ) { - - public static StepResponse of(List<ActionAppResponse> actions) { - if (actions.isEmpty()) { - return new StepResponse(List.of()); - } - List<ActionsResponse> actionsResponse = new ArrayList<>(); - Set<String> members = new HashSet<>(); - ActionAppResponse firstAction = getFirstAction(actions); - List<ActionAppResponse> group = new ArrayList<>(); - group.add(firstAction); - String currentActionType = firstAction.actionTypeName(); - members.add(firstAction.name()); - - for (int i = 1; i < actions.size(); i++) { - ActionAppResponse action = actions.get(i); - String typeName = action.actionTypeName(); - if (currentActionType.equals(typeName)) { - if (typeName.equals("IN")) { - members.add(action.name()); - } - if (typeName.equals("OUT")) { - members.remove(action.name()); - } - group.add(action); - continue; - } - actionsResponse.add(ActionsResponse.of(group, members)); - currentActionType = typeName; - group.clear(); - if (typeName.equals("IN")) { - members.add(action.name()); - } - if (typeName.equals("OUT")) { - members.remove(action.name()); - } - group.add(action); - } - actionsResponse.add(ActionsResponse.of(group, members)); - - return new StepResponse(actionsResponse); + public static StepResponse of(List<String> members, List<ActionAppResponse> actions) { + return new StepResponse( + actions.get(0).actionTypeName(), + new ArrayList<>(members), + toActionsResponse(actions) + ); } - private static ActionAppResponse getFirstAction(List<ActionAppResponse> actions) { - return actions.get(0); + private static List<ActionResponse> toActionsResponse(List<ActionAppResponse> actions) { + return actions.stream() + .map(ActionResponse::of) + .toList(); } } diff --git a/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java b/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java new file mode 100644 index 000000000..ac147387d --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java @@ -0,0 +1,52 @@ +package server.haengdong.presentation.response; + +import java.util.ArrayList; +import java.util.List; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.ActionAppResponse.ActionType; + +public record StepsResponse(List<StepResponse> steps) { + + public static StepsResponse of(List<ActionAppResponse> actions) { + List<StepResponse> steps = new ArrayList<>(); + List<String> currentMembers = new ArrayList<>(); + List<List<ActionAppResponse>> groups = createGroups(actions); + + for (List<ActionAppResponse> group : groups) { + changeCurrentMembers(group, currentMembers); + StepResponse stepResponse = StepResponse.of(currentMembers, group); + steps.add(stepResponse); + } + return new StepsResponse(steps); + } + + private static List<List<ActionAppResponse>> createGroups(List<ActionAppResponse> actions) { + List<List<ActionAppResponse>> groups = new ArrayList<>(); + + for (ActionAppResponse action : actions) { + if (groups.isEmpty() || isActionTypeChange(action, groups)) { + groups.add(new ArrayList<>()); + } + groups.get(groups.size() - 1).add(action); + } + + return groups; + } + + private static boolean isActionTypeChange(ActionAppResponse action, List<List<ActionAppResponse>> groups) { + List<ActionAppResponse> currentGroup = groups.get(groups.size() - 1); + return currentGroup.get(0).actionType() != action.actionType(); + } + + private static void changeCurrentMembers(List<ActionAppResponse> group, List<String> currentMembers) { + for (ActionAppResponse action : group) { + if (action.actionType() == ActionType.IN) { + currentMembers.add(action.name()); + continue; + } + if (action.actionType() == ActionType.OUT) { + currentMembers.remove(action.name()); + } + } + } +} diff --git a/server/src/test/java/server/haengdong/presentation/response/StepResponseTest.java b/server/src/test/java/server/haengdong/presentation/response/StepResponseTest.java deleted file mode 100644 index aac78691c..000000000 --- a/server/src/test/java/server/haengdong/presentation/response/StepResponseTest.java +++ /dev/null @@ -1,57 +0,0 @@ -package server.haengdong.presentation.response; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import java.util.ArrayList; -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import server.haengdong.application.response.ActionAppResponse; -import server.haengdong.application.response.ActionAppResponse.ActionType; - -@SpringBootTest -class StepResponseTest { - - @Autowired - private ObjectMapper objectMapper; - - @DisplayName("") - @Test - void test() throws JsonProcessingException { - List<ActionAppResponse> actionAppResponse = new ArrayList<>(); - - // IN actions - ActionAppResponse actionAppResponse1 = new ActionAppResponse(3L, "망쵸", null, 3L, ActionType.IN); - actionAppResponse.add(actionAppResponse1); - ActionAppResponse actionAppResponse2 = new ActionAppResponse(4L, "백호", null, 4L, ActionType.IN); - actionAppResponse.add(actionAppResponse2); - - // BILL step 1 - ActionAppResponse actionAppResponse3 = new ActionAppResponse(1L, "감자탕", 10000L, 1L, ActionType.BILL); - actionAppResponse.add(actionAppResponse3); - ActionAppResponse actionAppResponse4 = new ActionAppResponse(2L, "인생네컷", 10000L, 2L, ActionType.BILL); - actionAppResponse.add(actionAppResponse4); - - // IN actions - ActionAppResponse actionAppResponse5 = new ActionAppResponse(5L, "소하", null, 5L, ActionType.IN); - actionAppResponse.add(actionAppResponse5); - ActionAppResponse actionAppResponse6 = new ActionAppResponse(6L, "웨디", null, 6L, ActionType.IN); - actionAppResponse.add(actionAppResponse6); - - // OUT actions - ActionAppResponse actionAppResponse7 = new ActionAppResponse(7L, "망쵸", null, 7L, ActionType.OUT); - actionAppResponse.add(actionAppResponse7); - ActionAppResponse actionAppResponse8 = new ActionAppResponse(8L, "백호", null, 8L, ActionType.OUT); - actionAppResponse.add(actionAppResponse8); - - // BILL step 2 - ActionAppResponse actionAppResponse9 = new ActionAppResponse(9L, "노래방", 20000L, 10L, ActionType.BILL); - actionAppResponse.add(actionAppResponse9); - - // StepResponse creation - StepResponse stepResponse = StepResponse.of(actionAppResponse); - System.out.println("stepResponse = " + stepResponse); - } -} diff --git a/server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java b/server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java new file mode 100644 index 000000000..f8fdb6e7d --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java @@ -0,0 +1,63 @@ +package server.haengdong.presentation.response; + + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.ActionAppResponse.ActionType; + +class StepsResponseTest { + + @DisplayName("이웃한 같은 타입의 액션들을 그룹화 하여 응답객체를 생성한다.") + @Test + void of() { + List<ActionAppResponse> actions = List.of( + new ActionAppResponse(1L, "망쵸", null, 1L, ActionType.IN), + new ActionAppResponse(2L, "백호", null, 2L, ActionType.IN), + new ActionAppResponse(3L, "감자탕", 10_000L, 3L, ActionType.BILL), + new ActionAppResponse(4L, "인생네컷", 10_000L, 4L, ActionType.BILL), + new ActionAppResponse(5L, "소하", null, 5L, ActionType.IN), + new ActionAppResponse(6L, "웨디", null, 6L, ActionType.IN), + new ActionAppResponse(7L, "망쵸", null, 7L, ActionType.OUT), + new ActionAppResponse(8L, "백호", null, 8L, ActionType.OUT), + new ActionAppResponse(9L, "노래방", 20_000L, 9L, ActionType.BILL) + ); + + StepsResponse stepsResponse = StepsResponse.of(actions); + + StepsResponse expected = new StepsResponse( + List.of( + new StepResponse("IN", List.of("망쵸", "백호"), List.of( + new ActionResponse(1L, "망쵸", null, 1L), + new ActionResponse(2L, "백호", null, 2L) + )), + new StepResponse("BILL", List.of("망쵸", "백호"), List.of( + new ActionResponse(3L, "감자탕", 10_000L, 3L), + new ActionResponse(4L, "인생네컷", 10_000L, 4L) + )), + new StepResponse("IN", List.of("망쵸", "백호", "소하", "웨디"), List.of( + new ActionResponse(5L, "소하", null, 5L), + new ActionResponse(6L, "웨디", null, 6L) + )), + new StepResponse("OUT", List.of("소하", "웨디"), List.of( + new ActionResponse(7L, "망쵸", null, 7L), + new ActionResponse(8L, "백호", null, 8L) + )), + new StepResponse("BILL", List.of("소하", "웨디"), List.of( + new ActionResponse(9L, "노래방", 20_000L, 9L) + )) + ) + ); + assertThat(stepsResponse).isEqualTo(expected); + } + + @DisplayName("액션이 없으면 빈 스탭들이 만들어진다.") + @Test + void ofEmpty() { + StepsResponse stepsResponse = StepsResponse.of(List.of()); + assertThat(stepsResponse.steps()).isEmpty(); + } +} From 2768886e02b1cb6de76b4b11bbff8a7c85f2092d Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Sun, 4 Aug 2024 14:40:05 +0900 Subject: [PATCH 110/178] =?UTF-8?q?feat:=20=EB=A9=A4=EB=B2=84=20=EC=95=A1?= =?UTF-8?q?=EC=85=98=20=EC=82=AD=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(#181)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 액션 삭제 기능 구현 중 지출 삭제 가능, 인원 삭제는 아직입니다. * feat: 멤버 액션 삭제 구현 Co-authored-by: pakxe <pigkill40@naver.com> Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <gosmdochee2@gmail.com> * feat: 맴버 액션 삭제 기능 구현 * refactor: api 매개변수에 값 넣도록 수정 * fix: 테스트 코드에 action 올바르게 사용하도록 수정 --------- Co-authored-by: 김진호 <rlawlsgh1227@gmail.com> Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: pakxe <pigkill40@naver.com> --- .../application/MemberActionService.java | 13 +++++ .../domain/action/ActionRepository.java | 2 + .../domain/action/BillActionRepository.java | 4 ++ .../domain/action/MemberActionRepository.java | 12 ++++ .../exception/HaengdongErrorCode.java | 5 +- .../presentation/MemberActionController.java | 11 ++++ .../application/ActionServiceTest.java | 13 +++++ .../application/BillActionServiceTest.java | 14 ++++- .../application/MemberActionServiceTest.java | 55 ++++++++++++++++++- .../MemberActionControllerTest.java | 18 +++++- 10 files changed, 138 insertions(+), 9 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java index f893bd08d..64858d8d4 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionService.java +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -58,4 +58,17 @@ private Event findEvent(String token) { return eventRepository.findByToken(token) .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); } + + @Transactional + public void deleteMemberAction(String token, Long actionId) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + Action action = actionRepository.findByIdAndEvent(actionId, event) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_ACTION)); + MemberAction memberAction = memberActionRepository.findByAction(action) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_MEMBER_ACTION)); + + memberActionRepository.deleteAllByMemberNameAndMinSequence(memberAction.getMemberName(), + memberAction.getSequence()); + } } diff --git a/server/src/main/java/server/haengdong/domain/action/ActionRepository.java b/server/src/main/java/server/haengdong/domain/action/ActionRepository.java index c2138e42f..2fde0ffa6 100644 --- a/server/src/main/java/server/haengdong/domain/action/ActionRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/ActionRepository.java @@ -18,4 +18,6 @@ public interface ActionRepository extends JpaRepository<Action, Long> { LIMIT 1 """) Optional<Action> findLastByEvent(@Param("event") Event event); + + Optional<Action> findByIdAndEvent(Long id, Event event); } diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java index 1ad7416aa..468d03061 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java @@ -1,6 +1,8 @@ package server.haengdong.domain.action; import java.util.List; +import java.util.Optional; + import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @@ -11,4 +13,6 @@ public interface BillActionRepository extends JpaRepository<BillAction, Long> { @EntityGraph(attributePaths = {"action"}) List<BillAction> findByAction_Event(Event event); + + Optional<BillAction> findByAction(Action action); } diff --git a/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java index 6c4769e61..51248f305 100644 --- a/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java @@ -1,7 +1,9 @@ package server.haengdong.domain.action; import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @@ -12,4 +14,14 @@ public interface MemberActionRepository extends JpaRepository<MemberAction, Long @Query("select m from MemberAction m join fetch m.action where m.action.event = :event") List<MemberAction> findAllByEvent(@Param("event") Event event); + + Optional<MemberAction> findByAction(Action action); + + @Modifying + @Query(""" + delete + from MemberAction m + where m.memberName = :memberName and m.action.sequence >= :sequence + """) + void deleteAllByMemberNameAndMinSequence(String memberName, Long sequence); } diff --git a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java index 052b97fe2..55e48661a 100644 --- a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java +++ b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java @@ -10,9 +10,10 @@ public enum HaengdongErrorCode { DUPLICATED_MEMBER_ACTION("MA_001", "중복된 인원이 존재합니다."), INVALID_MEMBER_IN_ACTION("MA_002", "현재 참여하고 있는 인원이 존재합니다."), INVALID_MEMBER_OUT_ACTION("MA_003", "현재 참여하고 있지 않는 인원이 존재합니다."), + NOT_FOUND_MEMBER_ACTION("MA_400", "존재하지 않는 멤버 액션입니다."), NOT_FOUND_EVENT("EV_400", "존재하지 않는 행사입니다."), - INTERNAL_SERVER_ERROR("S_001", "서버 내부에서 에러가 발생했습니다."), - ; + NOT_FOUND_ACTION("AC_400", "존재하지 않는 액션입니다."), + INTERNAL_SERVER_ERROR("S_001", "서버 내부에서 에러가 발생했습니다."); private final String code; private final String message; diff --git a/server/src/main/java/server/haengdong/presentation/MemberActionController.java b/server/src/main/java/server/haengdong/presentation/MemberActionController.java index c12370d86..e2c61b33f 100644 --- a/server/src/main/java/server/haengdong/presentation/MemberActionController.java +++ b/server/src/main/java/server/haengdong/presentation/MemberActionController.java @@ -3,6 +3,7 @@ import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -36,4 +37,14 @@ public ResponseEntity<CurrentMembersResponse> getCurrentMembers(@PathVariable("e return ResponseEntity.ok() .body(CurrentMembersResponse.of(currentMembers)); } + + @DeleteMapping("/api/events/{eventId}/actions/{actionId}/members") + public ResponseEntity<Void> deleteMemberAction( + @PathVariable("eventId") String token, + @PathVariable("actionId") Long actionId + ) { + memberActionService.deleteMemberAction(token, actionId); + + return ResponseEntity.ok().build(); + } } diff --git a/server/src/test/java/server/haengdong/application/ActionServiceTest.java b/server/src/test/java/server/haengdong/application/ActionServiceTest.java index ac2dc4f4f..a05141b9b 100644 --- a/server/src/test/java/server/haengdong/application/ActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/ActionServiceTest.java @@ -7,12 +7,14 @@ import static server.haengdong.domain.action.MemberActionStatus.OUT; import java.util.List; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import server.haengdong.application.response.MemberBillReportAppResponse; import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.ActionRepository; import server.haengdong.domain.action.BillAction; import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.action.MemberAction; @@ -31,12 +33,23 @@ class ActionServiceTest { @Autowired private EventRepository eventRepository; + @Autowired + private ActionRepository actionRepository; + @Autowired private BillActionRepository billActionRepository; @Autowired private MemberActionRepository memberActionRepository; + @AfterEach + void tearDown() { + billActionRepository.deleteAllInBatch(); + memberActionRepository.deleteAllInBatch(); + actionRepository.deleteAllInBatch(); + eventRepository.deleteAllInBatch(); + } + @DisplayName("참여자별 정산 현황을 조회한다.") @Test void getMemberBillReports() { diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java index 195d4bdd9..e519eb5ac 100644 --- a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java @@ -5,14 +5,16 @@ import static org.assertj.core.api.Assertions.tuple; import java.util.List; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import server.haengdong.application.request.BillActionAppRequest; +import server.haengdong.domain.action.ActionRepository; import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.event.Event; import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.exception.HaengdongException; @@ -22,12 +24,22 @@ class BillActionServiceTest { @Autowired private BillActionService billActionService; + @Autowired + private ActionRepository actionRepository; + @Autowired private EventRepository eventRepository; @Autowired private BillActionRepository billActionRepository; + @AfterEach + void tearDown() { + billActionRepository.deleteAllInBatch(); + actionRepository.deleteAllInBatch(); + eventRepository.deleteAllInBatch(); + } + @DisplayName("지출 내역을 생성한다.") @Test void saveAllBillAction() { diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java index 7212e300d..9639f9570 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java @@ -1,7 +1,9 @@ package server.haengdong.application; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; import static server.haengdong.domain.action.MemberActionStatus.IN; import static server.haengdong.domain.action.MemberActionStatus.OUT; @@ -17,6 +19,7 @@ import server.haengdong.domain.action.ActionRepository; import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.action.MemberActionStatus; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.exception.HaengdongException; @@ -48,7 +51,7 @@ void tearDown() { void saveMemberActionTest() { Event event = eventRepository.save(new Event("test", "TOKEN")); Action action = new Action(event, 1L); - MemberAction memberAction = new MemberAction(action, "망쵸", IN, 1L); + MemberAction memberAction = createMemberAction(action, "망쵸", IN, 1L); memberActionRepository.save(memberAction); assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionsSaveAppRequest( @@ -61,11 +64,11 @@ void saveMemberActionTest() { void saveMemberActionTest1() { Event event = eventRepository.save(new Event("test", "TOKEN")); Action actionOne = new Action(event, 1L); - MemberAction memberActionOne = new MemberAction(actionOne, "망쵸", IN, 1L); + MemberAction memberActionOne = createMemberAction(actionOne, "망쵸", IN, 1L); memberActionRepository.save(memberActionOne); Action actionTwo = new Action(event, 2L); - MemberAction memberActionTwo = new MemberAction(actionTwo, "망쵸", OUT, 1L); + MemberAction memberActionTwo = createMemberAction(actionTwo, "망쵸", OUT, 1L); memberActionRepository.save(memberActionTwo); assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionsSaveAppRequest( @@ -89,4 +92,50 @@ void getCurrentMembers() { assertThatThrownBy(() -> memberActionService.getCurrentMembers("token")) .isInstanceOf(HaengdongException.class); } + + @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") + @Test + void deleteMemberAction() { + String token = "TOKEN"; + Event event = new Event("행동대장 회식", token); + eventRepository.save(event); + MemberAction memberAction1 = createMemberAction(new Action(event, 1L), "토다리", IN, 1L); + Action targetAction = new Action(event, 2L); + MemberAction memberAction2 = createMemberAction(targetAction, "토다리", OUT, 2L); + MemberAction memberAction3 = createMemberAction(new Action(event, 3L), "쿠키", IN, 3L); + MemberAction memberAction4 = createMemberAction(new Action(event, 4L), "웨디", IN, 4L); + MemberAction memberAction5 = createMemberAction(new Action(event, 5L), "토다리", IN, 5L); + MemberAction memberAction6 = createMemberAction(new Action(event, 6L), "토다리", OUT, 6L); + MemberAction memberAction7 = createMemberAction(new Action(event, 7L), "쿠키", OUT, 7L); + memberActionRepository.saveAll( + List.of(memberAction1, + memberAction2, + memberAction3, + memberAction4, + memberAction5, + memberAction6, + memberAction7) + ); + + memberActionService.deleteMemberAction(token, targetAction.getId()); + List<MemberAction> memberActions = memberActionRepository.findAll(); + + assertThat(memberActions).hasSize(4) + .extracting("id", "memberName", "status") + .containsExactly( + tuple(memberAction1.getId(), "토다리", IN), + tuple(memberAction3.getId(), "쿠키", IN), + tuple(memberAction4.getId(), "웨디", IN), + tuple(memberAction7.getId(), "쿠키", OUT) + ); + } + + private MemberAction createMemberAction( + Action action, + String memberName, + MemberActionStatus memberActionStatus, + long memberGroupId + ) { + return new MemberAction(action, memberName, memberActionStatus, memberGroupId); + } } diff --git a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java index ad8787cc6..22840f091 100644 --- a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java @@ -3,9 +3,11 @@ import static org.hamcrest.Matchers.equalTo; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.databind.ObjectMapper; @@ -17,7 +19,6 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import server.haengdong.application.MemberActionService; import server.haengdong.application.response.CurrentMemberAppResponse; import server.haengdong.presentation.request.MemberActionsSaveRequest; @@ -61,7 +62,18 @@ void getCurrentMembers() throws Exception { .accept(MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$.members[0].name").value(equalTo("소하"))) - .andExpect(MockMvcResultMatchers.jsonPath("$.members[1].name").value(equalTo("토다리"))); + .andExpect(jsonPath("$.members[0].name").value(equalTo("소하"))) + .andExpect(jsonPath("$.members[1].name").value(equalTo("토다리"))); + } + + @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") + @Test + void deleteMemberAction() throws Exception { + String token = "TOKEN"; + Long actionId = 2L; + + mockMvc.perform(delete("/api/events/{token}/actions/{actionId}/members", token, actionId)) + .andDo(print()) + .andExpect(status().isOk()); } } From 51c5c8970f2ffdebf0d5918989e268b279388fca Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Sun, 4 Aug 2024 14:50:17 +0900 Subject: [PATCH 111/178] =?UTF-8?q?feat:=20ERD=20svg=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=ED=95=98=EC=97=AC=20=EC=8A=A4=ED=82=A4=EB=A7=88=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=EC=97=90=20=EB=8C=80=ED=95=9C=20=EC=9D=B4=EB=A0=A5=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=20(#190)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/docs/24-08-04-erd.sql | 65 ++++++++++++++++++++++++++++++++++++ server/docs/24-08-04-erd.svg | 4 +++ 2 files changed, 69 insertions(+) create mode 100644 server/docs/24-08-04-erd.sql create mode 100644 server/docs/24-08-04-erd.svg diff --git a/server/docs/24-08-04-erd.sql b/server/docs/24-08-04-erd.sql new file mode 100644 index 000000000..ae2fbc4a5 --- /dev/null +++ b/server/docs/24-08-04-erd.sql @@ -0,0 +1,65 @@ +-- Create tables +CREATE TABLE action +( + event_id BIGINT, + id BIGINT AUTO_INCREMENT, + sequence BIGINT, + PRIMARY KEY (id) +); + +CREATE TABLE bill_action +( + action_id BIGINT UNIQUE, + id BIGINT AUTO_INCREMENT, + price BIGINT, + title VARCHAR(30), + PRIMARY KEY (id) +); + +CREATE TABLE event +( + id BIGINT AUTO_INCREMENT, + name VARCHAR(255), + token VARCHAR(255), + PRIMARY KEY (id) +); + +CREATE TABLE event_step +( + event_id BIGINT, + id BIGINT AUTO_INCREMENT, + sequence BIGINT, + name VARCHAR(255), + PRIMARY KEY (id) +); + +CREATE TABLE member_action +( + action_id BIGINT UNIQUE, + id BIGINT AUTO_INCREMENT, + member_group_id BIGINT, + member_name VARCHAR(255), + status ENUM('IN', 'OUT'), + PRIMARY KEY (id) +); + +-- Add foreign key constraints +ALTER TABLE action + ADD CONSTRAINT FKgf0qmub9va1xbe44nehny31yw + FOREIGN KEY (event_id) + REFERENCES event (id); + +ALTER TABLE bill_action + ADD CONSTRAINT FK54tx517tp0ry6453olkply4us + FOREIGN KEY (action_id) + REFERENCES action (id); + +ALTER TABLE event_step + ADD CONSTRAINT FKe3rkib91cvl0x5w9wqkshmn81 + FOREIGN KEY (event_id) + REFERENCES event (id); + +ALTER TABLE member_action + ADD CONSTRAINT FK5jna51dn8fs2ir52l4uwn517u + FOREIGN KEY (action_id) + REFERENCES action (id); diff --git a/server/docs/24-08-04-erd.svg b/server/docs/24-08-04-erd.svg new file mode 100644 index 000000000..5a4bac225 --- /dev/null +++ b/server/docs/24-08-04-erd.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Do not edit this file with editors other than draw.io --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1993px" height="1581px" viewBox="-0.5 -0.5 1993 1581" content="<mxfile host="app.diagrams.net" modified="2024-07-25T04:17:06.208Z" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36" etag="gR5VLfYLO6MRu5dHcV28" version="24.7.3" type="github"> <diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1"> <mxGraphModel dx="2380" dy="2150" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0"> <root> <mxCell id="WIyWlLk6GJQsqaUBKTNV-0" /> <mxCell id="WIyWlLk6GJQsqaUBKTNV-1" parent="WIyWlLk6GJQsqaUBKTNV-0" /> <mxCell id="8gZzuRhjrYuwNxX9kY4q-98" value="" style="rounded=0;whiteSpace=wrap;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="-442" y="-590" width="1992" height="1580" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-47" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;startArrow=ERone;startFill=0;endArrow=ERzeroToMany;endFill=0;dashed=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="8gZzuRhjrYuwNxX9kY4q-0" target="8gZzuRhjrYuwNxX9kY4q-37" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-66" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;startArrow=ERone;startFill=0;endArrow=ERzeroToMany;endFill=0;dashed=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="8gZzuRhjrYuwNxX9kY4q-0" target="8gZzuRhjrYuwNxX9kY4q-56" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-0" value="Event" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="40" y="40" width="280" height="120" as="geometry"> <mxRectangle x="480" y="530" width="70" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-1" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="8gZzuRhjrYuwNxX9kY4q-0" vertex="1"> <mxGeometry y="30" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-2" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-1" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-3" value="event_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-1" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-137" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-1" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-7" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-0" vertex="1"> <mxGeometry y="60" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-8" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-7" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-9" value="token" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-7" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-138" value="varchar(20)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-7" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-4" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-0" vertex="1"> <mxGeometry y="90" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-5" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-4" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-6" value="name" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-4" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-139" value="varchar(255)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-4" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-37" value="Event_Step" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="40" y="240" width="280" height="150" as="geometry"> <mxRectangle x="480" y="530" width="70" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-38" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="8gZzuRhjrYuwNxX9kY4q-37" vertex="1"> <mxGeometry y="30" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-39" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-38" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-40" value="event_step_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-38" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-143" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-38" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-41" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-37" vertex="1"> <mxGeometry y="60" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-42" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-41" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-43" value="name" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-41" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-144" value="varchar(30)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-41" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-44" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-37" vertex="1"> <mxGeometry y="90" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-45" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-44" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-46" value="sequence" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-44" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-145" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-44" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-48" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-37" vertex="1"> <mxGeometry y="120" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-49" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-48" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-50" value="event_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-48" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-146" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-48" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-77" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;startArrow=ERone;startFill=0;endArrow=ERone;endFill=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="8gZzuRhjrYuwNxX9kY4q-56" target="8gZzuRhjrYuwNxX9kY4q-67" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-91" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;startArrow=ERone;startFill=0;endArrow=ERone;endFill=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="8gZzuRhjrYuwNxX9kY4q-56" target="8gZzuRhjrYuwNxX9kY4q-81" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-56" value="Action" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="414" y="40" width="280" height="120" as="geometry"> <mxRectangle x="480" y="530" width="70" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-57" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="8gZzuRhjrYuwNxX9kY4q-56" vertex="1"> <mxGeometry y="30" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-58" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-57" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-59" value="action_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-57" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-140" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-57" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-60" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-56" vertex="1"> <mxGeometry y="60" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-61" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-60" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-62" value="sequence" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-60" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-141" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-60" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-63" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-56" vertex="1"> <mxGeometry y="90" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-64" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-63" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-65" value="event_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-63" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-142" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-63" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-67" value="Bill_Action" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="414" y="240" width="280" height="150" as="geometry"> <mxRectangle x="480" y="530" width="70" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-68" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="8gZzuRhjrYuwNxX9kY4q-67" vertex="1"> <mxGeometry y="30" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-69" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-68" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-70" value="bill_action_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-68" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-147" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-68" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-71" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-67" vertex="1"> <mxGeometry y="60" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-72" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-71" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-73" value="title" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-71" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-148" value="varchar(30)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-71" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-78" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-67" vertex="1"> <mxGeometry y="90" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-79" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-78" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-80" value="price" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-78" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-149" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-78" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-74" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-67" vertex="1"> <mxGeometry y="120" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-75" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-74" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-76" value="action_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-74" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-150" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-74" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-81" value="Member_Action" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="790" y="40" width="280" height="180" as="geometry"> <mxRectangle x="480" y="530" width="70" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-82" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="8gZzuRhjrYuwNxX9kY4q-81" vertex="1"> <mxGeometry y="30" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-83" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-82" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-84" value="member_action_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-82" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-151" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-82" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-85" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-81" vertex="1"> <mxGeometry y="60" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-86" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-85" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-87" value="member_name" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-85" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-152" value="varchar(20)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-85" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-92" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-81" vertex="1"> <mxGeometry y="90" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-93" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-92" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-94" value="status" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-92" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-153" value="varchar(10)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-92" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-95" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-81" vertex="1"> <mxGeometry y="120" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-96" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-95" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-97" value="member_group_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-95" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-154" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-95" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-88" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-81" vertex="1"> <mxGeometry y="150" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-89" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-88" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-90" value="action_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-88" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-155" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-88" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> </root> </mxGraphModel> </diagram> </mxfile> " resource="https://app.diagrams.net/?src=about#Hkunsanglee%2Fcafekiosk-study%2Fmain%2Fsrc%2Fmain%2Fresources%2Fexample2.svg#%7B%22pageId%22%3A%22C5RBs43oDa-KdzZeNtuy%22%7D"><defs/><g><g data-cell-id="WIyWlLk6GJQsqaUBKTNV-0"><g data-cell-id="WIyWlLk6GJQsqaUBKTNV-1"><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-98"><g><rect x="0" y="0" width="1992" height="1580" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-47"><g><path d="M 622 750 L 622 814.5" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 626 754 L 618 754" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="622" cy="818" rx="3" ry="3" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 626 830 L 622 822 L 618 830 M 622 822 L 622 830" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-66"><g><path d="M 762 690 L 840.5 690" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 766 686 L 766 694" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="844" cy="690" rx="3" ry="3" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 856 686 L 848 690 L 856 694 M 848 690 L 856 690" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-0"><g><path d="M 482 660 L 482 630 L 762 630 L 762 660" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 482 660 L 482 750 L 762 750 L 762 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 482 660 L 762 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 512 660 L 512 690 L 512 720 L 512 750" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 632 660 L 632 690 L 632 720 L 632 750" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 645px; margin-left: 622px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: nowrap;">Event</div></div></div></foreignObject><text x="622" y="649" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">Event</text></switch></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-1"><g><path d="M 482 660 M 762 660 M 762 690 L 482 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-2"><g><rect x="482" y="660" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 660 M 512 660 M 512 690 M 482 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 675px; margin-left: 483px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">PK</div></div></div></foreignObject><text x="497" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">PK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-3"><g><rect x="512" y="660" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 660 M 632 660 M 632 690 M 512 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 675px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">event_id</div></div></div></foreignObject><text x="520" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">event_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-137"><g><rect x="632" y="660" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 660 M 762 660 M 762 690 M 632 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 675px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="640" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-7"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-8"><g><rect x="482" y="690" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 690 M 512 690 M 512 720 M 482 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-9"><g><rect x="512" y="690" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 690 M 632 690 M 632 720 M 512 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 705px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">token</div></div></div></foreignObject><text x="520" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">token</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-138"><g><rect x="632" y="690" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 690 M 762 690 M 762 720 M 632 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 705px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(20)</div></div></div></foreignObject><text x="640" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(20)</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-4"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-5"><g><rect x="482" y="720" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 720 M 512 720 M 512 750 M 482 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-6"><g><rect x="512" y="720" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 720 M 632 720 M 632 750 M 512 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 735px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">name</div></div></div></foreignObject><text x="520" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">name</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-139"><g><rect x="632" y="720" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 720 M 762 720 M 762 750 M 632 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 735px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(255)</div></div></div></foreignObject><text x="640" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(255)</text></switch></g></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-37"><g><path d="M 482 860 L 482 830 L 762 830 L 762 860" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 482 860 L 482 980 L 762 980 L 762 860" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 482 860 L 762 860" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 512 860 L 512 890 L 512 920 L 512 950 L 512 980" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 632 860 L 632 890 L 632 920 L 632 950 L 632 980" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 845px; margin-left: 622px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: nowrap;">Event_Step</div></div></div></foreignObject><text x="622" y="849" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">Event_Step</text></switch></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-38"><g><path d="M 482 860 M 762 860 M 762 890 L 482 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-39"><g><rect x="482" y="860" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 860 M 512 860 M 512 890 M 482 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 875px; margin-left: 483px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">PK</div></div></div></foreignObject><text x="497" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">PK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-40"><g><rect x="512" y="860" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 860 M 632 860 M 632 890 M 512 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 875px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">event_step_id</div></div></div></foreignObject><text x="520" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">event_step_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-143"><g><rect x="632" y="860" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 860 M 762 860 M 762 890 M 632 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 875px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="640" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-41"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-42"><g><rect x="482" y="890" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 890 M 512 890 M 512 920 M 482 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-43"><g><rect x="512" y="890" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 890 M 632 890 M 632 920 M 512 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 905px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">name</div></div></div></foreignObject><text x="520" y="909" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">name</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-144"><g><rect x="632" y="890" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 890 M 762 890 M 762 920 M 632 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 905px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(30)</div></div></div></foreignObject><text x="640" y="909" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(30)</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-44"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-45"><g><rect x="482" y="920" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 920 M 512 920 M 512 950 M 482 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-46"><g><rect x="512" y="920" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 920 M 632 920 M 632 950 M 512 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 935px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">sequence</div></div></div></foreignObject><text x="520" y="939" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">sequence</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-145"><g><rect x="632" y="920" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 920 M 762 920 M 762 950 M 632 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 935px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="640" y="939" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-48"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-49"><g><rect x="482" y="950" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 950 M 512 950 M 512 980 M 482 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 965px; margin-left: 483px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FK</div></div></div></foreignObject><text x="497" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">FK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-50"><g><rect x="512" y="950" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 950 M 632 950 M 632 980 M 512 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 965px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">event_id</div></div></div></foreignObject><text x="520" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">event_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-146"><g><rect x="632" y="950" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 950 M 762 950 M 762 980 M 632 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 965px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="640" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-77"><g><path d="M 996 750 L 996 830" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 1000 754 L 992 754" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 992 826 L 1000 826" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-91"><g><path d="M 1136 690 L 1184 690 L 1184 720 L 1232 720" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 1140 686 L 1140 694" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 1228 724 L 1228 716" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-56"><g><path d="M 856 660 L 856 630 L 1136 630 L 1136 660" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 856 660 L 856 750 L 1136 750 L 1136 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 856 660 L 1136 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 886 660 L 886 690 L 886 720 L 886 750" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1006 660 L 1006 690 L 1006 720 L 1006 750" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 645px; margin-left: 996px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: nowrap;">Action</div></div></div></foreignObject><text x="996" y="649" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">Action</text></switch></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-57"><g><path d="M 856 660 M 1136 660 M 1136 690 L 856 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-58"><g><rect x="856" y="660" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 660 M 886 660 M 886 690 M 856 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 675px; margin-left: 857px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">PK</div></div></div></foreignObject><text x="871" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">PK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-59"><g><rect x="886" y="660" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 660 M 1006 660 M 1006 690 M 886 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 675px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">action_id</div></div></div></foreignObject><text x="894" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">action_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-140"><g><rect x="1006" y="660" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 660 M 1136 660 M 1136 690 M 1006 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 675px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-60"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-61"><g><rect x="856" y="690" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 690 M 886 690 M 886 720 M 856 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-62"><g><rect x="886" y="690" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 690 M 1006 690 M 1006 720 M 886 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 705px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">sequence</div></div></div></foreignObject><text x="894" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">sequence</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-141"><g><rect x="1006" y="690" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 690 M 1136 690 M 1136 720 M 1006 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 705px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-63"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-64"><g><rect x="856" y="720" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 720 M 886 720 M 886 750 M 856 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 735px; margin-left: 857px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FK</div></div></div></foreignObject><text x="871" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">FK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-65"><g><rect x="886" y="720" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 720 M 1006 720 M 1006 750 M 886 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 735px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">event_id</div></div></div></foreignObject><text x="894" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">event_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-142"><g><rect x="1006" y="720" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 720 M 1136 720 M 1136 750 M 1006 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 735px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-67"><g><path d="M 856 860 L 856 830 L 1136 830 L 1136 860" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 856 860 L 856 980 L 1136 980 L 1136 860" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 856 860 L 1136 860" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 886 860 L 886 890 L 886 920 L 886 950 L 886 980" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1006 860 L 1006 890 L 1006 920 L 1006 950 L 1006 980" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 845px; margin-left: 996px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: nowrap;">Bill_Action</div></div></div></foreignObject><text x="996" y="849" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">Bill_Action</text></switch></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-68"><g><path d="M 856 860 M 1136 860 M 1136 890 L 856 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-69"><g><rect x="856" y="860" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 860 M 886 860 M 886 890 M 856 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 875px; margin-left: 857px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">PK</div></div></div></foreignObject><text x="871" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">PK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-70"><g><rect x="886" y="860" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 860 M 1006 860 M 1006 890 M 886 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 875px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bill_action_id</div></div></div></foreignObject><text x="894" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bill_action_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-147"><g><rect x="1006" y="860" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 860 M 1136 860 M 1136 890 M 1006 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 875px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-71"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-72"><g><rect x="856" y="890" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 890 M 886 890 M 886 920 M 856 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-73"><g><rect x="886" y="890" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 890 M 1006 890 M 1006 920 M 886 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 905px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">title</div></div></div></foreignObject><text x="894" y="909" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">title</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-148"><g><rect x="1006" y="890" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 890 M 1136 890 M 1136 920 M 1006 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 905px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(30)</div></div></div></foreignObject><text x="1014" y="909" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(30)</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-78"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-79"><g><rect x="856" y="920" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 920 M 886 920 M 886 950 M 856 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-80"><g><rect x="886" y="920" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 920 M 1006 920 M 1006 950 M 886 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 935px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">price</div></div></div></foreignObject><text x="894" y="939" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">price</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-149"><g><rect x="1006" y="920" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 920 M 1136 920 M 1136 950 M 1006 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 935px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="939" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-74"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-75"><g><rect x="856" y="950" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 950 M 886 950 M 886 980 M 856 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 965px; margin-left: 857px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FK</div></div></div></foreignObject><text x="871" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">FK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-76"><g><rect x="886" y="950" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 950 M 1006 950 M 1006 980 M 886 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 965px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">action_id</div></div></div></foreignObject><text x="894" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">action_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-150"><g><rect x="1006" y="950" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 950 M 1136 950 M 1136 980 M 1006 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 965px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-81"><g><path d="M 1232 660 L 1232 630 L 1512 630 L 1512 660" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 1232 660 L 1232 810 L 1512 810 L 1512 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1232 660 L 1512 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1262 660 L 1262 690 L 1262 720 L 1262 750 L 1262 780 L 1262 810" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1382 660 L 1382 690 L 1382 720 L 1382 750 L 1382 780 L 1382 810" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 645px; margin-left: 1372px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: nowrap;">Member_Action</div></div></div></foreignObject><text x="1372" y="649" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">Member_Action</text></switch></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-82"><g><path d="M 1232 660 M 1512 660 M 1512 690 L 1232 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-83"><g><rect x="1232" y="660" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1232 660 M 1262 660 M 1262 690 M 1232 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 675px; margin-left: 1233px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">PK</div></div></div></foreignObject><text x="1247" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">PK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-84"><g><rect x="1262" y="660" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1262 660 M 1382 660 M 1382 690 M 1262 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 675px; margin-left: 1270px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">member_action_id</div></div></div></foreignObject><text x="1270" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">member_action_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-151"><g><rect x="1382" y="660" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1382 660 M 1512 660 M 1512 690 M 1382 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 675px; margin-left: 1390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1390" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-85"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-86"><g><rect x="1232" y="690" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1232 690 M 1262 690 M 1262 720 M 1232 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-87"><g><rect x="1262" y="690" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1262 690 M 1382 690 M 1382 720 M 1262 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 705px; margin-left: 1270px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">member_name</div></div></div></foreignObject><text x="1270" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">member_name</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-152"><g><rect x="1382" y="690" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1382 690 M 1512 690 M 1512 720 M 1382 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 705px; margin-left: 1390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(20)</div></div></div></foreignObject><text x="1390" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(20)</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-92"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-93"><g><rect x="1232" y="720" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1232 720 M 1262 720 M 1262 750 M 1232 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-94"><g><rect x="1262" y="720" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1262 720 M 1382 720 M 1382 750 M 1262 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 735px; margin-left: 1270px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">status</div></div></div></foreignObject><text x="1270" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">status</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-153"><g><rect x="1382" y="720" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1382 720 M 1512 720 M 1512 750 M 1382 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 735px; margin-left: 1390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(10)</div></div></div></foreignObject><text x="1390" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(10)</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-95"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-96"><g><rect x="1232" y="750" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1232 750 M 1262 750 M 1262 780 M 1232 780" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-97"><g><rect x="1262" y="750" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1262 750 M 1382 750 M 1382 780 M 1262 780" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 765px; margin-left: 1270px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">member_group_id</div></div></div></foreignObject><text x="1270" y="769" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">member_group_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-154"><g><rect x="1382" y="750" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1382 750 M 1512 750 M 1512 780 M 1382 780" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 765px; margin-left: 1390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1390" y="769" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-88"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-89"><g><rect x="1232" y="780" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1232 780 M 1262 780 M 1262 810 M 1232 810" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 795px; margin-left: 1233px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FK</div></div></div></foreignObject><text x="1247" y="799" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">FK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-90"><g><rect x="1262" y="780" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1262 780 M 1382 780 M 1382 810 M 1262 810" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 795px; margin-left: 1270px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">action_id</div></div></div></foreignObject><text x="1270" y="799" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">action_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-155"><g><rect x="1382" y="780" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1382 780 M 1512 780 M 1512 810 M 1382 810" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 795px; margin-left: 1390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1390" y="799" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g></g></g></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg> \ No newline at end of file From 3f93f2d17948ef2c17a3eac6568af5a80888fdba Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Sun, 4 Aug 2024 15:25:19 +0900 Subject: [PATCH 112/178] =?UTF-8?q?feat:=20=EC=A7=80=EC=B6=9C=20=EC=95=A1?= =?UTF-8?q?=EC=85=98=20=EC=88=98=EC=A0=95=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(#180)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/BillActionService.java | 31 +++++++++-- .../request/BillActionUpdateAppRequest.java | 7 +++ .../haengdong/domain/action/BillAction.java | 19 ++++++- .../domain/action/BillActionRepository.java | 3 +- .../server/haengdong/domain/event/Event.java | 4 ++ .../exception/HaengdongErrorCode.java | 6 ++- .../presentation/BillActionController.java | 14 +++++ .../request/BillActionUpdateRequest.java | 18 +++++++ .../application/BillActionServiceTest.java | 51 ++++++++++++++++++- .../BillActionControllerTest.java | 17 +++++++ 10 files changed, 159 insertions(+), 11 deletions(-) create mode 100644 server/src/main/java/server/haengdong/application/request/BillActionUpdateAppRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java index 257d33a3e..fa00fabd6 100644 --- a/server/src/main/java/server/haengdong/application/BillActionService.java +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -5,11 +5,12 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import server.haengdong.application.request.BillActionAppRequest; +import server.haengdong.application.request.BillActionUpdateAppRequest; import server.haengdong.domain.action.Action; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.event.Event; import server.haengdong.domain.action.ActionRepository; +import server.haengdong.domain.action.BillAction; import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.exception.HaengdongErrorCode; import server.haengdong.exception.HaengdongException; @@ -25,8 +26,7 @@ public class BillActionService { @Transactional public void saveAllBillAction(String eventToken, List<BillActionAppRequest> requests) { - Event event = eventRepository.findByToken(eventToken) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + Event event = getEvent(eventToken); Action action = createStartAction(event); for (BillActionAppRequest request : requests) { @@ -41,4 +41,27 @@ private Action createStartAction(Event event) { .map(Action::next) .orElse(Action.createFirst(event)); } + + @Transactional + public void updateBillAction(String token, Long actionId, BillActionUpdateAppRequest request) { + BillAction billAction = billActionRepository.findByAction_Id(actionId) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_BILL_ACTION)); + + validateToken(token, billAction); + + BillAction updatedBillAction = billAction.update(request.title(), request.price()); + billActionRepository.save(updatedBillAction); + } + + private void validateToken(String token, BillAction billAction) { + Event event = billAction.getEvent(); + if (event.isTokenMismatch(token)) { + throw new HaengdongException(HaengdongErrorCode.NOT_FOUND_BILL_ACTION); + } + } + + private Event getEvent(String eventToken) { + return eventRepository.findByToken(eventToken) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + } } diff --git a/server/src/main/java/server/haengdong/application/request/BillActionUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionUpdateAppRequest.java new file mode 100644 index 000000000..a90e3dd42 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/BillActionUpdateAppRequest.java @@ -0,0 +1,7 @@ +package server.haengdong.application.request; + +public record BillActionUpdateAppRequest( + String title, + Long price +) { +} diff --git a/server/src/main/java/server/haengdong/domain/action/BillAction.java b/server/src/main/java/server/haengdong/domain/action/BillAction.java index 1027206f5..273965755 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillAction.java +++ b/server/src/main/java/server/haengdong/domain/action/BillAction.java @@ -11,6 +11,7 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; +import server.haengdong.domain.event.Event; import server.haengdong.exception.HaengdongErrorCode; import server.haengdong.exception.HaengdongException; @@ -37,8 +38,13 @@ public class BillAction implements Comparable<BillAction> { private Long price; public BillAction(Action action, String title, Long price) { + this(null, action, title, price); + } + + private BillAction(Long id, Action action, String title, Long price) { validateTitle(title); validatePrice(price); + this.id = id; this.action = action; this.title = title.trim(); this.price = price; @@ -48,21 +54,30 @@ private void validateTitle(String title) { int titleLength = title.trim().length(); if (titleLength < MIN_TITLE_LENGTH || titleLength > MAX_TITLE_LENGTH) { throw new HaengdongException(HaengdongErrorCode.BAD_REQUEST, - String.format("앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다.", MIN_TITLE_LENGTH, MAX_TITLE_LENGTH)); + String.format("앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다.", MIN_TITLE_LENGTH, + MAX_TITLE_LENGTH)); } } private void validatePrice(Long price) { if (price < MIN_PRICE || price > MAX_PRICE) { throw new HaengdongException(HaengdongErrorCode.BAD_REQUEST, - String.format("지출 금액은 %,d 이하의 자연수여야 합니다.", MAX_PRICE)); + String.format("지출 금액은 %,d 이하의 자연수여야 합니다.", MAX_PRICE)); } } + public BillAction update(String title, Long price) { + return new BillAction(id, action, title, price); + } + public Long getSequence() { return action.getSequence(); } + public Event getEvent() { + return action.getEvent(); + } + @Override public int compareTo(BillAction o) { return Long.compare(this.getSequence(), o.getSequence()); diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java index 468d03061..389b498db 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java @@ -2,7 +2,6 @@ import java.util.List; import java.util.Optional; - import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @@ -14,5 +13,5 @@ public interface BillActionRepository extends JpaRepository<BillAction, Long> { @EntityGraph(attributePaths = {"action"}) List<BillAction> findByAction_Event(Event event); - Optional<BillAction> findByAction(Action action); + Optional<BillAction> findByAction_Id(Long actionId); } diff --git a/server/src/main/java/server/haengdong/domain/event/Event.java b/server/src/main/java/server/haengdong/domain/event/Event.java index 24369a184..17bffa44d 100644 --- a/server/src/main/java/server/haengdong/domain/event/Event.java +++ b/server/src/main/java/server/haengdong/domain/event/Event.java @@ -51,4 +51,8 @@ private void validateName(String name) { private boolean isBlankContinuous(String name) { return name.contains(SPACES); } + + public boolean isTokenMismatch(String token) { + return !this.token.equals(token); + } } diff --git a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java index 55e48661a..80b2cb6ae 100644 --- a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java +++ b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java @@ -7,13 +7,15 @@ public enum HaengdongErrorCode { BAD_REQUEST("R_001", "잘못된 요청입니다."), NO_RESOURCE_REQUEST("R_002", "잘못된 엔드포인트입니다."), MESSAGE_NOT_READABLE("R_003", "읽을 수 없는 요청 형식입니다."), + NOT_FOUND_EVENT("EV_400", "존재하지 않는 행사입니다."), DUPLICATED_MEMBER_ACTION("MA_001", "중복된 인원이 존재합니다."), INVALID_MEMBER_IN_ACTION("MA_002", "현재 참여하고 있는 인원이 존재합니다."), INVALID_MEMBER_OUT_ACTION("MA_003", "현재 참여하고 있지 않는 인원이 존재합니다."), NOT_FOUND_MEMBER_ACTION("MA_400", "존재하지 않는 멤버 액션입니다."), - NOT_FOUND_EVENT("EV_400", "존재하지 않는 행사입니다."), + NOT_FOUND_BILL_ACTION("BA_400", "존재하지 않는 지출 액션입니다."), NOT_FOUND_ACTION("AC_400", "존재하지 않는 액션입니다."), - INTERNAL_SERVER_ERROR("S_001", "서버 내부에서 에러가 발생했습니다."); + INTERNAL_SERVER_ERROR("S_001", "서버 내부에서 에러가 발생했습니다."), + ; private final String code; private final String message; diff --git a/server/src/main/java/server/haengdong/presentation/BillActionController.java b/server/src/main/java/server/haengdong/presentation/BillActionController.java index fcdacb270..7fe0a5ec0 100644 --- a/server/src/main/java/server/haengdong/presentation/BillActionController.java +++ b/server/src/main/java/server/haengdong/presentation/BillActionController.java @@ -5,10 +5,12 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import server.haengdong.application.BillActionService; import server.haengdong.presentation.request.BillActionsSaveRequest; +import server.haengdong.presentation.request.BillActionUpdateRequest; @RequiredArgsConstructor @RestController @@ -26,4 +28,16 @@ public ResponseEntity<Void> saveAllBillAction( return ResponseEntity.ok() .build(); } + + @PutMapping("/api/events/{eventId}/actions/bills/{actionId}") + public ResponseEntity<Void> updateBillAction( + @PathVariable("eventId") String token, + @PathVariable("actionId") Long actionId, + @Valid @RequestBody BillActionUpdateRequest request + ) { + billActionService.updateBillAction(token, actionId, request.toAppResponse()); + + return ResponseEntity.ok() + .build(); + } } diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java new file mode 100644 index 000000000..6f1a0a734 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java @@ -0,0 +1,18 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import server.haengdong.application.request.BillActionUpdateAppRequest; + +public record BillActionUpdateRequest( + + @NotBlank + String title, + + @NotNull + Long price +) { + public BillActionUpdateAppRequest toAppResponse() { + return new BillActionUpdateAppRequest(title, price); + } +} diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java index e519eb5ac..82ac51a4a 100644 --- a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.tuple; +import static org.junit.jupiter.api.Assertions.assertAll; import java.util.List; import org.junit.jupiter.api.AfterEach; @@ -11,6 +12,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import server.haengdong.application.request.BillActionAppRequest; +import server.haengdong.application.request.BillActionUpdateAppRequest; +import server.haengdong.domain.action.Action; import server.haengdong.domain.action.ActionRepository; import server.haengdong.domain.action.BillAction; import server.haengdong.domain.action.BillActionRepository; @@ -43,7 +46,7 @@ void tearDown() { @DisplayName("지출 내역을 생성한다.") @Test void saveAllBillAction() { - String token = "TOKEN"; + String token = "TOKEN2"; Event event = new Event("감자", token); Event savedEvent = eventRepository.save(event); @@ -74,4 +77,50 @@ void saveAllBillAction1() { assertThatThrownBy(() -> billActionService.saveAllBillAction("token", requests)) .isInstanceOf(HaengdongException.class); } + + @DisplayName("지출 액션을 수정한다.") + @Test + void updateBillAction() { + String token = "TOKEN"; + Event event = new Event("감자", token); + Event savedEvent = eventRepository.save(event); + Action action = Action.createFirst(savedEvent); + BillAction billAction = new BillAction(action, "뽕족", 10_000L); + BillAction savedBillAction = billActionRepository.save(billAction); + + Long actionId = savedBillAction.getAction().getId(); + BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L); + + billActionService.updateBillAction(token, actionId, request); + + BillAction updatedBillAction = billActionRepository.findById(savedBillAction.getId()).get(); + + assertAll( + () -> assertThat(updatedBillAction.getTitle()).isEqualTo("인생맥주"), + () -> assertThat(updatedBillAction.getPrice()).isEqualTo(20_000L) + ); + } + + @DisplayName("행사에 속하지 않은 지출 액션은 수정할 수 없다.") + @Test + void updateBillAction1() { + String token1 = "쿠키 토큰"; + String token2 = "웨디 토큰"; + Event event1 = new Event("감자1", token1); + Event event2 = new Event("감자2", token2); + Event savedEvent1 = eventRepository.save(event1); + Event savedEvent2 = eventRepository.save(event2); + Action action1 = Action.createFirst(savedEvent1); + Action action2 = Action.createFirst(savedEvent2); + BillAction billAction1 = new BillAction(action1, "뽕족", 10_000L); + BillAction billAction2 = new BillAction(action2, "뽕족", 10_000L); + BillAction savedBillAction1 = billActionRepository.save(billAction1); + billActionRepository.save(billAction2); + + Long actionId = savedBillAction1.getAction().getId(); + BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L); + + assertThatThrownBy(() -> billActionService.updateBillAction(token2, actionId, request)) + .isInstanceOf(HaengdongException.class); + } } diff --git a/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java index 8bf2b292f..bfd844b8e 100644 --- a/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java @@ -1,6 +1,7 @@ package server.haengdong.presentation; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -16,6 +17,7 @@ import server.haengdong.application.BillActionService; import server.haengdong.presentation.request.BillActionSaveRequest; import server.haengdong.presentation.request.BillActionsSaveRequest; +import server.haengdong.presentation.request.BillActionUpdateRequest; @WebMvcTest(BillActionController.class) class BillActionControllerTest { @@ -66,4 +68,19 @@ void saveAllBillAction1() throws Exception { .andDo(print()) .andExpect(status().isBadRequest()); } + + @DisplayName("지출 액션을 수정한다.") + @Test + void updateBillAction() throws Exception { + BillActionUpdateRequest request = new BillActionUpdateRequest("뽕족", 10_000L); + + String requestBody = objectMapper.writeValueAsString(request); + String token = "TOKEN"; + + mockMvc.perform(put("/api/events/{token}/actions/bills/{actionId}", token, 1L) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()); + } } From 24078cc11158142e1acb18ca80d07ddc44d53239 Mon Sep 17 00:00:00 2001 From: JUHA <84626225+khabh@users.noreply.github.com> Date: Sun, 4 Aug 2024 15:41:02 +0900 Subject: [PATCH 113/178] =?UTF-8?q?feat:=20=EC=A7=80=EC=B6=9C=20=EC=95=A1?= =?UTF-8?q?=EC=85=98=20=EC=82=AD=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(#179)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/BillActionService.java | 8 ++++++ .../haengdong/domain/action/BillAction.java | 5 ++-- .../domain/action/BillActionRepository.java | 2 ++ .../domain/event/EventRepository.java | 2 +- .../presentation/BillActionController.java | 14 +++++++++- .../application/BillActionServiceTest.java | 22 +++++++++++++++ .../BillActionControllerTest.java | 27 +++++++++++++++++++ 7 files changed, 75 insertions(+), 5 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java index fa00fabd6..68abb466e 100644 --- a/server/src/main/java/server/haengdong/application/BillActionService.java +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -64,4 +64,12 @@ private Event getEvent(String eventToken) { return eventRepository.findByToken(eventToken) .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); } + + @Transactional + public void deleteBillAction(String token, Long actionId) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + + billActionRepository.deleteByAction_EventAndActionId(event, actionId); + } } diff --git a/server/src/main/java/server/haengdong/domain/action/BillAction.java b/server/src/main/java/server/haengdong/domain/action/BillAction.java index 273965755..738b04d39 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillAction.java +++ b/server/src/main/java/server/haengdong/domain/action/BillAction.java @@ -54,15 +54,14 @@ private void validateTitle(String title) { int titleLength = title.trim().length(); if (titleLength < MIN_TITLE_LENGTH || titleLength > MAX_TITLE_LENGTH) { throw new HaengdongException(HaengdongErrorCode.BAD_REQUEST, - String.format("앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다.", MIN_TITLE_LENGTH, - MAX_TITLE_LENGTH)); + String.format("앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다.", MIN_TITLE_LENGTH, MAX_TITLE_LENGTH)); } } private void validatePrice(Long price) { if (price < MIN_PRICE || price > MAX_PRICE) { throw new HaengdongException(HaengdongErrorCode.BAD_REQUEST, - String.format("지출 금액은 %,d 이하의 자연수여야 합니다.", MAX_PRICE)); + String.format("지출 금액은 %,d 이하의 자연수여야 합니다.", MAX_PRICE)); } } diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java index 389b498db..a0e6a1bf1 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java @@ -13,5 +13,7 @@ public interface BillActionRepository extends JpaRepository<BillAction, Long> { @EntityGraph(attributePaths = {"action"}) List<BillAction> findByAction_Event(Event event); + void deleteByAction_EventAndActionId(Event event, Long actionId); + Optional<BillAction> findByAction_Id(Long actionId); } diff --git a/server/src/main/java/server/haengdong/domain/event/EventRepository.java b/server/src/main/java/server/haengdong/domain/event/EventRepository.java index 6038c368b..09526125e 100644 --- a/server/src/main/java/server/haengdong/domain/event/EventRepository.java +++ b/server/src/main/java/server/haengdong/domain/event/EventRepository.java @@ -6,6 +6,6 @@ @Repository public interface EventRepository extends JpaRepository<Event, Long> { - + Optional<Event> findByToken(String token); } diff --git a/server/src/main/java/server/haengdong/presentation/BillActionController.java b/server/src/main/java/server/haengdong/presentation/BillActionController.java index 7fe0a5ec0..251f69831 100644 --- a/server/src/main/java/server/haengdong/presentation/BillActionController.java +++ b/server/src/main/java/server/haengdong/presentation/BillActionController.java @@ -3,14 +3,15 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import server.haengdong.application.BillActionService; -import server.haengdong.presentation.request.BillActionsSaveRequest; import server.haengdong.presentation.request.BillActionUpdateRequest; +import server.haengdong.presentation.request.BillActionsSaveRequest; @RequiredArgsConstructor @RestController @@ -40,4 +41,15 @@ public ResponseEntity<Void> updateBillAction( return ResponseEntity.ok() .build(); } + + @DeleteMapping("/api/events/{eventId}/actions/{actionId}/bills") + public ResponseEntity<Void> deleteBillAction( + @PathVariable("eventId") String token, + @PathVariable("actionId") Long actionId + ) { + billActionService.deleteBillAction(token, actionId); + + return ResponseEntity.ok() + .build(); + } } diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java index 82ac51a4a..98e0b13b1 100644 --- a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java @@ -123,4 +123,26 @@ void updateBillAction1() { assertThatThrownBy(() -> billActionService.updateBillAction(token2, actionId, request)) .isInstanceOf(HaengdongException.class); } + + @DisplayName("지출 내역을 삭제한다.") + @Test + void deleteBillAction() { + String token = "토다리 토큰"; + Event event = new Event("감자", token); + eventRepository.save(event); + BillAction billAction = new BillAction(new Action(event, 1L), "커피", 50_900L); + billActionRepository.save(billAction); + Long actionId = billAction.getAction().getId(); + + billActionService.deleteBillAction(token, actionId); + + assertThat(billActionRepository.findById(billAction.getId())).isEmpty(); + } + + @DisplayName("지출 내역 삭제 시 행사가 존재하지 않으면 예외가 발생한다.") + @Test + void deleteBillAction1() { + assertThatThrownBy(() -> billActionService.deleteBillAction("소하망쵸", 1L)) + .isInstanceOf(HaengdongException.class); + } } diff --git a/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java index bfd844b8e..3170707d6 100644 --- a/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java @@ -1,5 +1,8 @@ package server.haengdong.presentation; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doThrow; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; @@ -15,6 +18,8 @@ import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import server.haengdong.application.BillActionService; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; import server.haengdong.presentation.request.BillActionSaveRequest; import server.haengdong.presentation.request.BillActionsSaveRequest; import server.haengdong.presentation.request.BillActionUpdateRequest; @@ -83,4 +88,26 @@ void updateBillAction() throws Exception { .andDo(print()) .andExpect(status().isOk()); } + + @DisplayName("지출 내역을 삭제한다.") + @Test + void deleteBillAction() throws Exception { + String token = "토다리토큰"; + + mockMvc.perform(delete("/api/events/{token}/actions/{actionId}/bills", token, 1)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("존재하지 않는 행사에 대한 지출 내역을 삭제할 수 없다.") + @Test + void deleteBillAction1() throws Exception { + String token = "TOKEN19348"; + doThrow(new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)) + .when(billActionService).deleteBillAction(any(String.class), any(Long.class)); + + mockMvc.perform(delete("/api/events/{token}/actions/{actionId}/bills", token, 1)) + .andDo(print()) + .andExpect(status().isBadRequest()); + } } From b76cf5398f0a5ccda8876c662415bfce8c364c33 Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Sun, 4 Aug 2024 16:00:27 +0900 Subject: [PATCH 114/178] =?UTF-8?q?feat:=20=ED=96=89=EC=82=AC=EC=9D=98=20?= =?UTF-8?q?=EC=A0=84=EC=B2=B4=20=EC=B0=B8=EC=97=AC=EC=9E=90=20=EC=A4=91=20?= =?UTF-8?q?=ED=8A=B9=EC=A0=95=20=EC=B0=B8=EC=97=AC=EC=9E=90=EC=9D=98=20?= =?UTF-8?q?=EB=A9=A4=EB=B2=84=20=EC=95=A1=EC=85=98=EC=9D=84=20=EB=AA=A8?= =?UTF-8?q?=EB=91=90=20=EC=82=AD=EC=A0=9C=ED=95=98=EB=8A=94=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84=20(#185)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 행사의 전체 참여자 중 특정 참여자의 멤버 액션을 모두 삭제하는 기능 구현 * test: eventId String으로 변경 * fix: 다른 행사에 있는 멤버 액션도 지워지는 버그 수정 * refactor: 전체 참여자 중에서 특정 참여자를 전부 삭제하는 메서드명 변경 * refactor: 전체 참여자 중에서 특정 참여자를 전부 삭제하는 메서드명 변경 * refactor: MemberActionController 메서드 파라미터 컨벤션 반영 * refactor: conflict resolve * refactor: conflict resolve --- .../application/MemberActionService.java | 7 +++ .../domain/action/MemberActionRepository.java | 8 ++++ .../presentation/MemberActionController.java | 10 +++++ .../application/MemberActionServiceTest.java | 45 +++++++++++++++++-- .../MemberActionControllerTest.java | 11 +++++ 5 files changed, 77 insertions(+), 4 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java index 64858d8d4..749771259 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionService.java +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -59,6 +59,13 @@ private Event findEvent(String token) { .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); } + public void deleteMember(String token, String memberName) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + + memberActionRepository.deleteAllByEventAndMemberName(event, memberName); + } + @Transactional public void deleteMemberAction(String token, Long actionId) { Event event = eventRepository.findByToken(token) diff --git a/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java index 51248f305..ebc2ffc2b 100644 --- a/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java @@ -15,6 +15,14 @@ public interface MemberActionRepository extends JpaRepository<MemberAction, Long @Query("select m from MemberAction m join fetch m.action where m.action.event = :event") List<MemberAction> findAllByEvent(@Param("event") Event event); + @Modifying + @Query(""" + delete + from MemberAction m + where m.memberName = :memberName and m.action.event = :event + """) + void deleteAllByEventAndMemberName(Event event, String memberName); + Optional<MemberAction> findByAction(Action action); @Modifying diff --git a/server/src/main/java/server/haengdong/presentation/MemberActionController.java b/server/src/main/java/server/haengdong/presentation/MemberActionController.java index e2c61b33f..3ac8028bf 100644 --- a/server/src/main/java/server/haengdong/presentation/MemberActionController.java +++ b/server/src/main/java/server/haengdong/presentation/MemberActionController.java @@ -38,6 +38,16 @@ public ResponseEntity<CurrentMembersResponse> getCurrentMembers(@PathVariable("e .body(CurrentMembersResponse.of(currentMembers)); } + @DeleteMapping("/api/events/{eventId}/members/{memberName}") + public ResponseEntity<Void> deleteMember( + @PathVariable("eventId") String token, + @PathVariable("memberName") String memberName + ) { + memberActionService.deleteMember(token, memberName); + + return ResponseEntity.ok().build(); + } + @DeleteMapping("/api/events/{eventId}/actions/{actionId}/members") public ResponseEntity<Void> deleteMemberAction( @PathVariable("eventId") String token, diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java index 9639f9570..d8b1334fc 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java @@ -3,7 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.assertj.core.api.Assertions.tuple; +import static org.assertj.core.groups.Tuple.tuple; import static server.haengdong.domain.action.MemberActionStatus.IN; import static server.haengdong.domain.action.MemberActionStatus.OUT; @@ -51,7 +51,7 @@ void tearDown() { void saveMemberActionTest() { Event event = eventRepository.save(new Event("test", "TOKEN")); Action action = new Action(event, 1L); - MemberAction memberAction = createMemberAction(action, "망쵸", IN, 1L); + MemberAction memberAction = new MemberAction(action, "망쵸", IN, 1L); memberActionRepository.save(memberAction); assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionsSaveAppRequest( @@ -64,11 +64,11 @@ void saveMemberActionTest() { void saveMemberActionTest1() { Event event = eventRepository.save(new Event("test", "TOKEN")); Action actionOne = new Action(event, 1L); - MemberAction memberActionOne = createMemberAction(actionOne, "망쵸", IN, 1L); + MemberAction memberActionOne = new MemberAction(actionOne, "망쵸", IN, 1L); memberActionRepository.save(memberActionOne); Action actionTwo = new Action(event, 2L); - MemberAction memberActionTwo = createMemberAction(actionTwo, "망쵸", OUT, 1L); + MemberAction memberActionTwo = new MemberAction(actionTwo, "망쵸", OUT, 1L); memberActionRepository.save(memberActionTwo); assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionsSaveAppRequest( @@ -93,6 +93,43 @@ void getCurrentMembers() { .isInstanceOf(HaengdongException.class); } + @DisplayName("행사의 전체 참여자 중에서 특정 참여자의 맴버 액션을 전부 삭제한다.") + @Test + void deleteMember() { + String token = "TOKEN"; + Event event = new Event("행동대장 회식", token); + eventRepository.save(event); + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "참여자", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "토다리", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "쿠키", IN, 1L); + MemberAction memberAction4 = new MemberAction(new Action(event, 4L), "소하", IN, 1L); + MemberAction memberAction5 = new MemberAction(new Action(event, 5L), "웨디", IN, 1L); + MemberAction memberAction6 = new MemberAction(new Action(event, 6L), "참여자", OUT, 1L); + memberActionRepository.saveAll( + List.of(memberAction1, memberAction2, memberAction3, memberAction4, memberAction5, memberAction6)); + + String token2 = "TOKEN2"; + Event event2 = new Event("옆동네 회식", token2); + eventRepository.save(event2); + Action action2 = Action.createFirst(event2); + MemberAction anotherMemberAction = new MemberAction(action2, "참여자", IN, 1L); + memberActionRepository.save(anotherMemberAction); + + memberActionService.deleteMember(token, "참여자"); + + List<MemberAction> memberActions = memberActionRepository.findAll(); + + assertThat(memberActions).hasSize(5) + .extracting("memberName", "status") + .containsExactly( + tuple("토다리", IN), + tuple("쿠키", IN), + tuple("소하", IN), + tuple("웨디", IN), + tuple("참여자", IN) + ); + } + @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") @Test void deleteMemberAction() { diff --git a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java index 22840f091..8a2f5661d 100644 --- a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java @@ -76,4 +76,15 @@ void deleteMemberAction() throws Exception { .andDo(print()) .andExpect(status().isOk()); } + + @DisplayName("행사의 전체 참여자 중에서 특정 참여자의 맴버 액션을 전부 삭제한다.") + @Test + void deleteMember() throws Exception { + String eventId = "TOKEN"; + String memberName = "행동대장"; + + mockMvc.perform(delete("/api/events/{eventId}/members/{memberName}", eventId, memberName)) + .andDo(print()) + .andExpect(status().isOk()); + } } From a7c942e63c16d7c3e501554d0ad7d5e9119c780c Mon Sep 17 00:00:00 2001 From: Juhwan Kim <13selfesteem91@naver.com> Date: Mon, 5 Aug 2024 14:52:46 +0900 Subject: [PATCH 115/178] =?UTF-8?q?feat:=20=ED=96=89=EC=82=AC=EC=97=90=20?= =?UTF-8?q?=EC=B0=B8=EC=97=AC=ED=95=9C=20=EC=A0=84=EC=B2=B4=20=EC=9D=B8?= =?UTF-8?q?=EC=9B=90=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(#195)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 행사에 참여한 전체 인원 조회 기능 구현 Co-authored-by: 3juhwan <13selfesteem91@naver.com> * refactor: EventServiceTest, MemberActionRepository 코드 리팩터링 * fix: workflows runs-on self-hosted로 변경 Co-authored-by: 3juhwan <13selfesteem91@naver.com> * fix: workflows runs-on self-hosted로 변경 Co-authored-by: 3juhwan <13selfesteem91@naver.com> * fix: workflows runs-on self-hosted로 변경 Co-authored-by: 3juhwan <13selfesteem91@naver.com> --------- Co-authored-by: kunsanglee <gosmdochee2@gmail.com> --- .github/workflows/backend-dev.yml | 2 +- .github/workflows/backend-pull-request.yml | 2 +- .../haengdong/application/EventService.java | 10 +++++++ .../response/MembersAppResponse.java | 8 +++++ .../domain/action/MemberActionRepository.java | 7 +++++ .../presentation/EventController.java | 8 +++++ .../response/MembersResponse.java | 13 ++++++++ .../application/EventServiceTest.java | 30 +++++++++++++++++-- .../presentation/EventControllerTest.java | 17 +++++++++++ 9 files changed, 92 insertions(+), 5 deletions(-) create mode 100644 server/src/main/java/server/haengdong/application/response/MembersAppResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/MembersResponse.java diff --git a/.github/workflows/backend-dev.yml b/.github/workflows/backend-dev.yml index 9e56c7615..4494c494f 100644 --- a/.github/workflows/backend-dev.yml +++ b/.github/workflows/backend-dev.yml @@ -8,7 +8,7 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: [ self-hosted, backend-dev ] defaults: run: diff --git a/.github/workflows/backend-pull-request.yml b/.github/workflows/backend-pull-request.yml index 797f88326..7e0c561f1 100644 --- a/.github/workflows/backend-pull-request.yml +++ b/.github/workflows/backend-pull-request.yml @@ -8,7 +8,7 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: [ self-hosted, backend-dev ] defaults: run: diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java index 9ad502606..e48a2dff2 100644 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -10,6 +10,7 @@ import server.haengdong.application.response.ActionAppResponse; import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.application.response.MembersAppResponse; import server.haengdong.domain.action.BillAction; import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.action.MemberAction; @@ -88,4 +89,13 @@ private List<ActionAppResponse> getActionAppResponses( return actionAppResponses; } + + public MembersAppResponse findAllMembers(String token) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + + List<String> memberNames = memberActionRepository.findAllUniqueMemberByEvent(event); + + return new MembersAppResponse(memberNames); + } } diff --git a/server/src/main/java/server/haengdong/application/response/MembersAppResponse.java b/server/src/main/java/server/haengdong/application/response/MembersAppResponse.java new file mode 100644 index 000000000..be8378b37 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/MembersAppResponse.java @@ -0,0 +1,8 @@ +package server.haengdong.application.response; + +import java.util.List; + +public record MembersAppResponse( + List<String> memberNames +) { +} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java index ebc2ffc2b..4d47bc009 100644 --- a/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java @@ -15,6 +15,13 @@ public interface MemberActionRepository extends JpaRepository<MemberAction, Long @Query("select m from MemberAction m join fetch m.action where m.action.event = :event") List<MemberAction> findAllByEvent(@Param("event") Event event); + @Query(""" + select distinct m.memberName + from MemberAction m + where m.action.event = :event + """) + List<String> findAllUniqueMemberByEvent(Event event); + @Modifying @Query(""" delete diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java index 816e7ed26..45f8362cd 100644 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -12,6 +12,7 @@ import server.haengdong.presentation.request.EventSaveRequest; import server.haengdong.presentation.response.EventDetailResponse; import server.haengdong.presentation.response.EventResponse; +import server.haengdong.presentation.response.MembersResponse; import server.haengdong.presentation.response.StepsResponse; @RequiredArgsConstructor @@ -40,4 +41,11 @@ public ResponseEntity<StepsResponse> findActions(@PathVariable("eventId") String return ResponseEntity.ok(stepsResponse); } + + @GetMapping("/api/events/{eventId}/members") + public ResponseEntity<MembersResponse> findAllMembers(@PathVariable("eventId") String token) { + MembersResponse response = MembersResponse.of(eventService.findAllMembers(token)); + + return ResponseEntity.ok(response); + } } diff --git a/server/src/main/java/server/haengdong/presentation/response/MembersResponse.java b/server/src/main/java/server/haengdong/presentation/response/MembersResponse.java new file mode 100644 index 000000000..0947d9e02 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/MembersResponse.java @@ -0,0 +1,13 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import server.haengdong.application.response.MembersAppResponse; + +public record MembersResponse( + List<String> memberNames +) { + + public static MembersResponse of(MembersAppResponse response) { + return new MembersResponse(response.memberNames()); + } +} diff --git a/server/src/test/java/server/haengdong/application/EventServiceTest.java b/server/src/test/java/server/haengdong/application/EventServiceTest.java index 5a3e8bce3..2affe0690 100644 --- a/server/src/test/java/server/haengdong/application/EventServiceTest.java +++ b/server/src/test/java/server/haengdong/application/EventServiceTest.java @@ -4,6 +4,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; import static org.mockito.BDDMockito.given; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; import java.util.List; import org.junit.jupiter.api.AfterEach; @@ -16,13 +18,13 @@ import server.haengdong.application.response.ActionAppResponse; import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.application.response.MembersAppResponse; import server.haengdong.domain.action.Action; import server.haengdong.domain.action.ActionRepository; import server.haengdong.domain.action.BillAction; import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionRepository; -import server.haengdong.domain.action.MemberActionStatus; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.domain.event.EventTokenProvider; @@ -84,9 +86,9 @@ void findEventTest() { void findActionsTest() { Event event = new Event("행동대장 회식", "웨디_토큰"); Action action = new Action(event, 1L); - MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + MemberAction memberAction = new MemberAction(action, "토다리", IN, 1L); Action action1 = new Action(event, 2L); - MemberAction memberAction1 = new MemberAction(action1, "쿠키", MemberActionStatus.IN, 1L); + MemberAction memberAction1 = new MemberAction(action1, "쿠키", IN, 1L); Action action2 = new Action(event, 3L); BillAction billAction = new BillAction(action2, "뽕나무쟁이족발", 30000L); eventRepository.save(event); @@ -107,4 +109,26 @@ void findActionsTest() { tuple(3L, "뽕나무쟁이족발", 30000L, 3L, "BILL") ); } + + @DisplayName("행사에 참여한 전체 인원을 중복 없이 조회한다.") + @Test + void findAllMembersTest() { + String token = "웨디_토큰"; + Event event = new Event("행동대장 회식", token); + Action action1 = new Action(event, 1L); + Action action2 = new Action(event, 2L); + Action action3 = new Action(event, 3L); + Action action4 = new Action(event, 4L); + BillAction billAction = new BillAction(action3, "뽕나무쟁이족발", 30000L); + MemberAction memberAction1 = new MemberAction(action1, "토다리", IN, 1L); + MemberAction memberAction2 = new MemberAction(action2, "쿠키", IN, 1L); + MemberAction memberAction3 = new MemberAction(action4, "쿠키", OUT, 1L); + eventRepository.save(event); + billActionRepository.save(billAction); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); + + MembersAppResponse membersAppResponse = eventService.findAllMembers(token); + + assertThat(membersAppResponse.memberNames()).containsExactlyInAnyOrder("토다리", "쿠키"); + } } diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java index 55a48630f..4a7a50d2d 100644 --- a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java @@ -1,6 +1,7 @@ package server.haengdong.presentation; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.given; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -9,6 +10,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -20,6 +22,7 @@ import server.haengdong.application.request.EventAppRequest; import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.application.response.MembersAppResponse; import server.haengdong.presentation.request.EventSaveRequest; @WebMvcTest(EventController.class) @@ -63,4 +66,18 @@ void findEventTest() throws Exception { .andExpect(status().isOk()) .andExpect(jsonPath("$.eventName").value("행동대장 회식")); } + + @DisplayName("행사에 참여한 전체 인원을 중복 없이 조회한다.") + @Test + void findAllMembersTest() throws Exception { + MembersAppResponse memberAppResponse = new MembersAppResponse(List.of("토다리", "쿠키")); + given(eventService.findAllMembers(anyString())).willReturn(memberAppResponse); + + mockMvc.perform(get("/api/events/{eventId}/members", "TOKEN")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.memberNames").isArray()) + .andExpect(jsonPath("$.memberNames[0]").value("토다리")) + .andExpect(jsonPath("$.memberNames[1]").value("쿠키")); + } } From 135fdd62f6c5ec77898baf9bcd71e740b959ae70 Mon Sep 17 00:00:00 2001 From: JUHA <84626225+khabh@users.noreply.github.com> Date: Mon, 5 Aug 2024 15:09:48 +0900 Subject: [PATCH 116/178] =?UTF-8?q?feat:=20=ED=96=89=EC=82=AC=20=EC=B0=B8?= =?UTF-8?q?=EC=97=AC=20=EC=9D=B8=EC=9B=90=20=EC=9D=B4=EB=A6=84=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20(#197)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 행사 참여 인원 이름 변경 기능 구현 * refactor: 지출 액션 수정 기능 리펙토링 --------- Co-authored-by: Arachneee <jhg2819@naver.com> --- .../haengdong/application/EventService.java | 19 +++++++ .../request/MemberUpdateAppRequest.java | 4 ++ .../haengdong/domain/action/MemberAction.java | 4 +- .../domain/action/MemberActionRepository.java | 4 ++ .../exception/HaengdongErrorCode.java | 3 +- .../presentation/EventController.java | 13 +++++ .../request/MemberUpdateRequest.java | 13 +++++ .../application/EventServiceTest.java | 49 +++++++++++++++++++ .../presentation/EventControllerTest.java | 16 ++++++ 9 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 server/src/main/java/server/haengdong/application/request/MemberUpdateAppRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/MemberUpdateRequest.java diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java index e48a2dff2..52080ae8f 100644 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -7,6 +7,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.request.MemberUpdateAppRequest; import server.haengdong.application.response.ActionAppResponse; import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; @@ -98,4 +99,22 @@ public MembersAppResponse findAllMembers(String token) { return new MembersAppResponse(memberNames); } + + @Transactional + public void updateMember(String token, String memberName, MemberUpdateAppRequest request) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + String updatedMemberName = request.name(); + validateMemberNameUnique(event, updatedMemberName); + + memberActionRepository.findAllByAction_EventAndMemberName(event, memberName) + .forEach(memberAction -> memberAction.updateMemberName(updatedMemberName)); + } + + private void validateMemberNameUnique(Event event, String updatedMemberName) { + boolean isMemberNameExist = memberActionRepository.existsByAction_EventAndMemberName(event, updatedMemberName); + if (isMemberNameExist) { + throw new HaengdongException(HaengdongErrorCode.DUPLICATED_MEMBER_NAME); + } + } } diff --git a/server/src/main/java/server/haengdong/application/request/MemberUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberUpdateAppRequest.java new file mode 100644 index 000000000..cbef9dda9 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberUpdateAppRequest.java @@ -0,0 +1,4 @@ +package server.haengdong.application.request; + +public record MemberUpdateAppRequest(String name) { +} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberAction.java b/server/src/main/java/server/haengdong/domain/action/MemberAction.java index 67387cbde..1e78820b2 100644 --- a/server/src/main/java/server/haengdong/domain/action/MemberAction.java +++ b/server/src/main/java/server/haengdong/domain/action/MemberAction.java @@ -39,8 +39,8 @@ public MemberAction(Action action, String memberName, MemberActionStatus status, this.memberGroupId = memberGroupId; } - public boolean isSameName(String name) { - return memberName.equals(name); + public void updateMemberName(String memberName) { + this.memberName = memberName; } public boolean isIn() { diff --git a/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java index 4d47bc009..8cf9e42cf 100644 --- a/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java @@ -39,4 +39,8 @@ public interface MemberActionRepository extends JpaRepository<MemberAction, Long where m.memberName = :memberName and m.action.sequence >= :sequence """) void deleteAllByMemberNameAndMinSequence(String memberName, Long sequence); + + List<MemberAction> findAllByAction_EventAndMemberName(Event event, String memberName); + + boolean existsByAction_EventAndMemberName(Event event, String updatedMemberName); } diff --git a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java index 80b2cb6ae..c9f461c5f 100644 --- a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java +++ b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java @@ -7,6 +7,8 @@ public enum HaengdongErrorCode { BAD_REQUEST("R_001", "잘못된 요청입니다."), NO_RESOURCE_REQUEST("R_002", "잘못된 엔드포인트입니다."), MESSAGE_NOT_READABLE("R_003", "읽을 수 없는 요청 형식입니다."), + INTERNAL_SERVER_ERROR("S_001", "서버 내부에서 에러가 발생했습니다."), + DUPLICATED_MEMBER_NAME("EV_001", "중복된 행사 참여 인원 이름이 존재합니다."), NOT_FOUND_EVENT("EV_400", "존재하지 않는 행사입니다."), DUPLICATED_MEMBER_ACTION("MA_001", "중복된 인원이 존재합니다."), INVALID_MEMBER_IN_ACTION("MA_002", "현재 참여하고 있는 인원이 존재합니다."), @@ -14,7 +16,6 @@ public enum HaengdongErrorCode { NOT_FOUND_MEMBER_ACTION("MA_400", "존재하지 않는 멤버 액션입니다."), NOT_FOUND_BILL_ACTION("BA_400", "존재하지 않는 지출 액션입니다."), NOT_FOUND_ACTION("AC_400", "존재하지 않는 액션입니다."), - INTERNAL_SERVER_ERROR("S_001", "서버 내부에서 에러가 발생했습니다."), ; private final String code; diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java index 45f8362cd..b6be87911 100644 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -6,10 +6,12 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import server.haengdong.application.EventService; import server.haengdong.presentation.request.EventSaveRequest; +import server.haengdong.presentation.request.MemberUpdateRequest; import server.haengdong.presentation.response.EventDetailResponse; import server.haengdong.presentation.response.EventResponse; import server.haengdong.presentation.response.MembersResponse; @@ -48,4 +50,15 @@ public ResponseEntity<MembersResponse> findAllMembers(@PathVariable("eventId") S return ResponseEntity.ok(response); } + + @PutMapping("/api/events/{eventId}/members/{memberName}") + public ResponseEntity<Void> updateMember( + @PathVariable("eventId") String token, + @PathVariable("memberName") String memberName, + @Valid @RequestBody MemberUpdateRequest request + ) { + eventService.updateMember(token, memberName, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } } diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberUpdateRequest.java new file mode 100644 index 000000000..71f0b4ec7 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MemberUpdateRequest.java @@ -0,0 +1,13 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import server.haengdong.application.request.MemberUpdateAppRequest; + +public record MemberUpdateRequest( + @NotBlank String name +) { + + public MemberUpdateAppRequest toAppRequest() { + return new MemberUpdateAppRequest(name); + } +} diff --git a/server/src/test/java/server/haengdong/application/EventServiceTest.java b/server/src/test/java/server/haengdong/application/EventServiceTest.java index 2affe0690..91a260829 100644 --- a/server/src/test/java/server/haengdong/application/EventServiceTest.java +++ b/server/src/test/java/server/haengdong/application/EventServiceTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.tuple; import static org.mockito.BDDMockito.given; import static server.haengdong.domain.action.MemberActionStatus.IN; @@ -15,6 +16,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.request.MemberUpdateAppRequest; import server.haengdong.application.response.ActionAppResponse; import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; @@ -28,6 +30,7 @@ import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.domain.event.EventTokenProvider; +import server.haengdong.exception.HaengdongException; @SpringBootTest class EventServiceTest { @@ -131,4 +134,50 @@ void findAllMembersTest() { assertThat(membersAppResponse.memberNames()).containsExactlyInAnyOrder("토다리", "쿠키"); } + + @DisplayName("행사 참여 인원의 이름을 변경한다.") + @Test + void updateMember() { + String token = "행동대장 회식"; + Event event = new Event("행동대장 회식", token); + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "토다리", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "쿠키", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "웨디", IN, 2L); + MemberAction memberAction4 = new MemberAction(new Action(event, 4L), "쿠키", OUT, 3L); + MemberAction memberAction5 = new MemberAction(new Action(event, 5L), "쿠키", IN, 4L); + MemberAction memberAction6 = new MemberAction(new Action(event, 6L), "쿠키", OUT, 5L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of( + memberAction1, memberAction2, memberAction3, memberAction4, memberAction5, memberAction6 + )); + + eventService.updateMember(token, "쿠키", new MemberUpdateAppRequest("쿡쿡")); + + List<MemberAction> foundMemberActions = memberActionRepository.findAllByEvent(event); + assertThat(foundMemberActions) + .extracting(MemberAction::getId, MemberAction::getMemberName) + .contains( + tuple(memberAction1.getId(), "토다리"), + tuple(memberAction2.getId(), "쿡쿡"), + tuple(memberAction3.getId(), "웨디"), + tuple(memberAction4.getId(), "쿡쿡"), + tuple(memberAction5.getId(), "쿡쿡"), + tuple(memberAction6.getId(), "쿡쿡") + ); + } + + @DisplayName("참여 인원 이름을 이미 존재하는 행사 참여 인원과 동일한 이름으로 변경할 수 없다.") + @Test + void updateMember1() { + String token = "행동대장 회식"; + Event event = new Event("행동대장 회식", token); + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "토다리", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "쿠키", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "웨디", IN, 2L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); + + assertThatThrownBy(() -> eventService.updateMember(token, "쿠키", new MemberUpdateAppRequest("토다리"))) + .isInstanceOf(HaengdongException.class); + } } diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java index 4a7a50d2d..1f3d6edaa 100644 --- a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java @@ -5,6 +5,7 @@ import static org.mockito.BDDMockito.given; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -24,6 +25,7 @@ import server.haengdong.application.response.EventDetailAppResponse; import server.haengdong.application.response.MembersAppResponse; import server.haengdong.presentation.request.EventSaveRequest; +import server.haengdong.presentation.request.MemberUpdateRequest; @WebMvcTest(EventController.class) class EventControllerTest { @@ -80,4 +82,18 @@ void findAllMembersTest() throws Exception { .andExpect(jsonPath("$.memberNames[0]").value("토다리")) .andExpect(jsonPath("$.memberNames[1]").value("쿠키")); } + + @DisplayName("행사 참여 인원의 이름을 수정한다.") + @Test + void updateMember() throws Exception { + String token = "TOKEN"; + MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest("변경된 이름"); + String requestBody = objectMapper.writeValueAsString(memberUpdateRequest); + + mockMvc.perform(put("/api/events/{eventId}/members/{memberName}", token, "변경 전 이름") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()); + } } From 475ca1b08245d5cb657f998b6e2011b84d9d3085 Mon Sep 17 00:00:00 2001 From: JUHA <84626225+khabh@users.noreply.github.com> Date: Mon, 5 Aug 2024 15:16:03 +0900 Subject: [PATCH 117/178] =?UTF-8?q?refactor:=20API=20=EC=97=94=EB=93=9C?= =?UTF-8?q?=ED=8F=AC=EC=9D=B8=ED=8A=B8=20=EC=88=98=EC=A0=95=20(#200)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 멤버 액션, 지출 액션 관련 API 엔드포인트 수정 * refactor: 요청 url에 token을 eventId로 수정 --------- Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: Arachne <66822642+Arachneee@users.noreply.github.com> --- .../presentation/BillActionController.java | 6 +++--- .../presentation/MemberActionController.java | 4 ++-- .../presentation/ActionControllerTest.java | 2 +- .../BillActionControllerTest.java | 20 +++++++++---------- .../presentation/EventControllerTest.java | 12 +++++------ .../MemberActionControllerTest.java | 10 +++++----- 6 files changed, 27 insertions(+), 27 deletions(-) diff --git a/server/src/main/java/server/haengdong/presentation/BillActionController.java b/server/src/main/java/server/haengdong/presentation/BillActionController.java index 251f69831..94cd1666b 100644 --- a/server/src/main/java/server/haengdong/presentation/BillActionController.java +++ b/server/src/main/java/server/haengdong/presentation/BillActionController.java @@ -19,7 +19,7 @@ public class BillActionController { private final BillActionService billActionService; - @PostMapping("/api/events/{eventId}/actions/bills") + @PostMapping("/api/events/{eventId}/bill-actions") public ResponseEntity<Void> saveAllBillAction( @PathVariable("eventId") String token, @RequestBody @Valid BillActionsSaveRequest request @@ -30,7 +30,7 @@ public ResponseEntity<Void> saveAllBillAction( .build(); } - @PutMapping("/api/events/{eventId}/actions/bills/{actionId}") + @PutMapping("/api/events/{eventId}/bill-actions/{actionId}") public ResponseEntity<Void> updateBillAction( @PathVariable("eventId") String token, @PathVariable("actionId") Long actionId, @@ -42,7 +42,7 @@ public ResponseEntity<Void> updateBillAction( .build(); } - @DeleteMapping("/api/events/{eventId}/actions/{actionId}/bills") + @DeleteMapping("/api/events/{eventId}/bill-actions/{actionId}") public ResponseEntity<Void> deleteBillAction( @PathVariable("eventId") String token, @PathVariable("actionId") Long actionId diff --git a/server/src/main/java/server/haengdong/presentation/MemberActionController.java b/server/src/main/java/server/haengdong/presentation/MemberActionController.java index 3ac8028bf..1703245f7 100644 --- a/server/src/main/java/server/haengdong/presentation/MemberActionController.java +++ b/server/src/main/java/server/haengdong/presentation/MemberActionController.java @@ -20,7 +20,7 @@ public class MemberActionController { private final MemberActionService memberActionService; - @PostMapping("/api/events/{eventId}/actions/members") + @PostMapping("/api/events/{eventId}/member-actions") public ResponseEntity<Void> saveMemberAction( @PathVariable("eventId") String token, @RequestBody MemberActionsSaveRequest request @@ -48,7 +48,7 @@ public ResponseEntity<Void> deleteMember( return ResponseEntity.ok().build(); } - @DeleteMapping("/api/events/{eventId}/actions/{actionId}/members") + @DeleteMapping("/api/events/{eventId}/member-actions/{actionId}") public ResponseEntity<Void> deleteMemberAction( @PathVariable("eventId") String token, @PathVariable("actionId") Long actionId diff --git a/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java index 739ac4962..ce1345917 100644 --- a/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java @@ -36,7 +36,7 @@ void getMemberBillReports() throws Exception { given(actionService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); - mockMvc.perform(get("/api/events/{token}/actions/reports", "token") + mockMvc.perform(get("/api/events/{eventId}/actions/reports", "망쵸토큰") .accept(MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) diff --git a/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java index 3170707d6..901e31b6d 100644 --- a/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java @@ -46,9 +46,9 @@ void saveAllBillAction() throws Exception { ) ); String requestBody = objectMapper.writeValueAsString(request); - String token = "TOKEN"; + String eventId = "쿠키토큰"; - mockMvc.perform(post("/api/events/{token}/actions/bills", token) + mockMvc.perform(post("/api/events/{eventId}/bill-actions", eventId) .contentType(MediaType.APPLICATION_JSON) .content(requestBody)) .andDo(print()) @@ -65,9 +65,9 @@ void saveAllBillAction1() throws Exception { ) ); String requestBody = objectMapper.writeValueAsString(request); - String token = "TOKEN"; + String eventId = "소하토큰"; - mockMvc.perform(post("/api/events/{token}/actions/bills", token) + mockMvc.perform(post("/api/events/{eventId}/bill-actions", eventId) .contentType(MediaType.APPLICATION_JSON) .content(requestBody)) .andDo(print()) @@ -80,9 +80,9 @@ void updateBillAction() throws Exception { BillActionUpdateRequest request = new BillActionUpdateRequest("뽕족", 10_000L); String requestBody = objectMapper.writeValueAsString(request); - String token = "TOKEN"; + String eventId = "웨디토큰"; - mockMvc.perform(put("/api/events/{token}/actions/bills/{actionId}", token, 1L) + mockMvc.perform(put("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1L) .contentType(MediaType.APPLICATION_JSON) .content(requestBody)) .andDo(print()) @@ -92,9 +92,9 @@ void updateBillAction() throws Exception { @DisplayName("지출 내역을 삭제한다.") @Test void deleteBillAction() throws Exception { - String token = "토다리토큰"; + String eventId = "토다리토큰"; - mockMvc.perform(delete("/api/events/{token}/actions/{actionId}/bills", token, 1)) + mockMvc.perform(delete("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1)) .andDo(print()) .andExpect(status().isOk()); } @@ -102,11 +102,11 @@ void deleteBillAction() throws Exception { @DisplayName("존재하지 않는 행사에 대한 지출 내역을 삭제할 수 없다.") @Test void deleteBillAction1() throws Exception { - String token = "TOKEN19348"; + String eventId = "이상해토큰"; doThrow(new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)) .when(billActionService).deleteBillAction(any(String.class), any(Long.class)); - mockMvc.perform(delete("/api/events/{token}/actions/{actionId}/bills", token, 1)) + mockMvc.perform(delete("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1)) .andDo(print()) .andExpect(status().isBadRequest()); } diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java index 1f3d6edaa..347b734bb 100644 --- a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java @@ -44,8 +44,8 @@ class EventControllerTest { void saveEvent() throws Exception { EventSaveRequest eventSaveRequest = new EventSaveRequest("토다리"); String requestBody = objectMapper.writeValueAsString(eventSaveRequest); - String token = "TOKEN"; - EventAppResponse eventAppResponse = new EventAppResponse(token); + String eventId = "망쵸토큰"; + EventAppResponse eventAppResponse = new EventAppResponse(eventId); given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); mockMvc.perform(post("/api/events") @@ -53,17 +53,17 @@ void saveEvent() throws Exception { .content(requestBody)) .andDo(print()) .andExpect(status().isOk()) - .andExpect(jsonPath("$.eventId").value("TOKEN")); + .andExpect(jsonPath("$.eventId").value("망쵸토큰")); } @DisplayName("토큰으로 행사를 조회한다.") @Test void findEventTest() throws Exception { - String token = "TOKEN"; + String eventId = "망쵸토큰"; EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식"); - given(eventService.findEvent(token)).willReturn(eventDetailAppResponse); + given(eventService.findEvent(eventId)).willReturn(eventDetailAppResponse); - mockMvc.perform(get("/api/events/" + token)) + mockMvc.perform(get("/api/events/{eventId}", eventId)) .andDo(print()) .andExpect(status().isOk()) .andExpect(jsonPath("$.eventName").value("행동대장 회식")); diff --git a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java index 8a2f5661d..a195311d1 100644 --- a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java @@ -43,7 +43,7 @@ void saveMemberActionTest() throws Exception { String requestBody = objectMapper.writeValueAsString(memberActionsSaveRequest); - mockMvc.perform(post("/api/events/TOKEN/actions/members") + mockMvc.perform(post("/api/events/{eventId}/member-actions", "망쵸토큰") .contentType(MediaType.APPLICATION_JSON) .content(requestBody)) .andDo(print()) @@ -58,7 +58,7 @@ void getCurrentMembers() throws Exception { given(memberActionService.getCurrentMembers(any())).willReturn(currentMemberAppResponses); - mockMvc.perform(get("/api/events/{token}/members/current", "token") + mockMvc.perform(get("/api/events/{eventId}/members/current", "망쵸토큰") .accept(MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) @@ -69,10 +69,10 @@ void getCurrentMembers() throws Exception { @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") @Test void deleteMemberAction() throws Exception { - String token = "TOKEN"; + String eventId = "망쵸토큰"; Long actionId = 2L; - mockMvc.perform(delete("/api/events/{token}/actions/{actionId}/members", token, actionId)) + mockMvc.perform(delete("/api/events/{eventId}/member-actions/{actionId}", eventId, actionId)) .andDo(print()) .andExpect(status().isOk()); } @@ -80,7 +80,7 @@ void deleteMemberAction() throws Exception { @DisplayName("행사의 전체 참여자 중에서 특정 참여자의 맴버 액션을 전부 삭제한다.") @Test void deleteMember() throws Exception { - String eventId = "TOKEN"; + String eventId = "망쵸토큰"; String memberName = "행동대장"; mockMvc.perform(delete("/api/events/{eventId}/members/{memberName}", eventId, memberName)) From b2258acfdc22ff12ed37fc255e18c863b72eb676 Mon Sep 17 00:00:00 2001 From: Juhwan Kim <13selfesteem91@naver.com> Date: Mon, 5 Aug 2024 15:40:17 +0900 Subject: [PATCH 118/178] =?UTF-8?q?feat:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=ED=81=B4=EB=A6=AC=EB=84=88=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20(#199)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 테스트 데이터 클리너 구현 * feat: 테스트 클리너 상수, 메서드 분리 * refactor: 데이터베이스 클리너 적용 --- .../application/ActionServiceTest.java | 16 ++---- .../application/BillActionServiceTest.java | 14 ++--- .../application/EventServiceTest.java | 28 ++++------ .../application/MemberActionFactoryTest.java | 21 +++----- .../application/MemberActionServiceTest.java | 17 ++---- .../support/extension/DatabaseCleaner.java | 52 +++++++++++++++++++ .../extension/DatabaseCleanerExtension.java | 19 +++++++ 7 files changed, 96 insertions(+), 71 deletions(-) create mode 100644 server/src/test/java/server/haengdong/support/extension/DatabaseCleaner.java create mode 100644 server/src/test/java/server/haengdong/support/extension/DatabaseCleanerExtension.java diff --git a/server/src/test/java/server/haengdong/application/ActionServiceTest.java b/server/src/test/java/server/haengdong/application/ActionServiceTest.java index a05141b9b..159bdd68e 100644 --- a/server/src/test/java/server/haengdong/application/ActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/ActionServiceTest.java @@ -7,14 +7,13 @@ import static server.haengdong.domain.action.MemberActionStatus.OUT; import java.util.List; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import server.haengdong.application.response.MemberBillReportAppResponse; import server.haengdong.domain.action.Action; -import server.haengdong.domain.action.ActionRepository; import server.haengdong.domain.action.BillAction; import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.action.MemberAction; @@ -23,7 +22,9 @@ import server.haengdong.domain.event.EventRepository; import server.haengdong.exception.HaengdongErrorCode; import server.haengdong.exception.HaengdongException; +import server.haengdong.support.extension.DatabaseCleanerExtension; +@ExtendWith(DatabaseCleanerExtension.class) @SpringBootTest class ActionServiceTest { @@ -33,23 +34,12 @@ class ActionServiceTest { @Autowired private EventRepository eventRepository; - @Autowired - private ActionRepository actionRepository; - @Autowired private BillActionRepository billActionRepository; @Autowired private MemberActionRepository memberActionRepository; - @AfterEach - void tearDown() { - billActionRepository.deleteAllInBatch(); - memberActionRepository.deleteAllInBatch(); - actionRepository.deleteAllInBatch(); - eventRepository.deleteAllInBatch(); - } - @DisplayName("참여자별 정산 현황을 조회한다.") @Test void getMemberBillReports() { diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java index 98e0b13b1..76b576542 100644 --- a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java @@ -6,9 +6,9 @@ import static org.junit.jupiter.api.Assertions.assertAll; import java.util.List; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import server.haengdong.application.request.BillActionAppRequest; @@ -20,29 +20,21 @@ import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.exception.HaengdongException; +import server.haengdong.support.extension.DatabaseCleanerExtension; +@ExtendWith(DatabaseCleanerExtension.class) @SpringBootTest class BillActionServiceTest { @Autowired private BillActionService billActionService; - @Autowired - private ActionRepository actionRepository; - @Autowired private EventRepository eventRepository; @Autowired private BillActionRepository billActionRepository; - @AfterEach - void tearDown() { - billActionRepository.deleteAllInBatch(); - actionRepository.deleteAllInBatch(); - eventRepository.deleteAllInBatch(); - } - @DisplayName("지출 내역을 생성한다.") @Test void saveAllBillAction() { diff --git a/server/src/test/java/server/haengdong/application/EventServiceTest.java b/server/src/test/java/server/haengdong/application/EventServiceTest.java index 91a260829..bf85d1bc3 100644 --- a/server/src/test/java/server/haengdong/application/EventServiceTest.java +++ b/server/src/test/java/server/haengdong/application/EventServiceTest.java @@ -9,9 +9,9 @@ import static server.haengdong.domain.action.MemberActionStatus.OUT; import java.util.List; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; @@ -22,7 +22,6 @@ import server.haengdong.application.response.EventDetailAppResponse; import server.haengdong.application.response.MembersAppResponse; import server.haengdong.domain.action.Action; -import server.haengdong.domain.action.ActionRepository; import server.haengdong.domain.action.BillAction; import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.action.MemberAction; @@ -30,36 +29,27 @@ import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.domain.event.EventTokenProvider; +import server.haengdong.support.extension.DatabaseCleanerExtension; import server.haengdong.exception.HaengdongException; +@ExtendWith(DatabaseCleanerExtension.class) @SpringBootTest class EventServiceTest { @Autowired private EventService eventService; - @MockBean - private EventTokenProvider eventTokenProvider; - @Autowired private EventRepository eventRepository; - @Autowired - private ActionRepository actionRepository; - @Autowired private BillActionRepository billActionRepository; @Autowired private MemberActionRepository memberActionRepository; - @AfterEach - void tearDown() { - billActionRepository.deleteAllInBatch(); - memberActionRepository.deleteAllInBatch(); - actionRepository.deleteAllInBatch(); - eventRepository.deleteAllInBatch(); - } + @MockBean + private EventTokenProvider eventTokenProvider; @DisplayName("행사를 생성한다") @Test @@ -102,10 +92,10 @@ void findActionsTest() { assertThat(actionAppResponses).hasSize(3) .extracting(ActionAppResponse::actionId, - ActionAppResponse::name, - ActionAppResponse::price, - ActionAppResponse::sequence, - ActionAppResponse::actionTypeName) + ActionAppResponse::name, + ActionAppResponse::price, + ActionAppResponse::sequence, + ActionAppResponse::actionTypeName) .containsExactly( tuple(1L, "토다리", null, 1L, "IN"), tuple(2L, "쿠키", null, 2L, "IN"), diff --git a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java index 278423759..2c2a978ae 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java @@ -6,23 +6,24 @@ import static org.assertj.core.api.Assertions.tuple; import java.util.List; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import server.haengdong.application.request.MemberActionSaveAppRequest; import server.haengdong.application.request.MemberActionsSaveAppRequest; import server.haengdong.domain.action.Action; import server.haengdong.domain.action.CurrentMembers; -import server.haengdong.domain.event.Event; import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; import server.haengdong.domain.action.MemberActionStatus; -import server.haengdong.domain.action.ActionRepository; +import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; -import server.haengdong.domain.action.MemberActionRepository; import server.haengdong.exception.HaengdongException; +import server.haengdong.support.extension.DatabaseCleanerExtension; +@ExtendWith(DatabaseCleanerExtension.class) @SpringBootTest class MemberActionFactoryTest { @@ -32,19 +33,9 @@ class MemberActionFactoryTest { @Autowired private MemberActionRepository memberActionRepository; - @Autowired - private ActionRepository actionRepository; - @Autowired private EventRepository eventRepository; - @AfterEach - void tearDown() { - memberActionRepository.deleteAllInBatch(); - actionRepository.deleteAllInBatch(); - eventRepository.deleteAllInBatch(); - } - @DisplayName("이전 멤버 액션이 시퀀스 기준으로 정렬되지 않은 상태에서 새로운 멤버 액션 요청을 검증한다.") @Test void createMemberActionsTest() { @@ -80,7 +71,7 @@ void createMemberActionsTest1() { CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); List<MemberAction> memberActions = memberActionFactory.createMemberActions(memberActionsSaveAppRequest, - currentMembers, startAction + currentMembers, startAction ); assertThat(memberActions).hasSize(1) diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java index d8b1334fc..5bc9fd1ea 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java @@ -8,22 +8,23 @@ import static server.haengdong.domain.action.MemberActionStatus.OUT; import java.util.List; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import server.haengdong.application.request.MemberActionSaveAppRequest; import server.haengdong.application.request.MemberActionsSaveAppRequest; import server.haengdong.domain.action.Action; -import server.haengdong.domain.action.ActionRepository; import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionRepository; import server.haengdong.domain.action.MemberActionStatus; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.exception.HaengdongException; +import server.haengdong.support.extension.DatabaseCleanerExtension; +@ExtendWith(DatabaseCleanerExtension.class) @SpringBootTest class MemberActionServiceTest { @@ -36,16 +37,6 @@ class MemberActionServiceTest { @Autowired private EventRepository eventRepository; - @Autowired - private ActionRepository actionRepository; - - @AfterEach - void tearDown() { - memberActionRepository.deleteAllInBatch(); - actionRepository.deleteAllInBatch(); - eventRepository.deleteAllInBatch(); - } - @DisplayName("현재 행사에 참여하고 있는 경우에 나갈 수 있다.") @Test void saveMemberActionTest() { @@ -118,7 +109,7 @@ void deleteMember() { memberActionService.deleteMember(token, "참여자"); List<MemberAction> memberActions = memberActionRepository.findAll(); - + assertThat(memberActions).hasSize(5) .extracting("memberName", "status") .containsExactly( diff --git a/server/src/test/java/server/haengdong/support/extension/DatabaseCleaner.java b/server/src/test/java/server/haengdong/support/extension/DatabaseCleaner.java new file mode 100644 index 000000000..346e81d2d --- /dev/null +++ b/server/src/test/java/server/haengdong/support/extension/DatabaseCleaner.java @@ -0,0 +1,52 @@ +package server.haengdong.support.extension; + +import jakarta.annotation.PostConstruct; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import java.util.List; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +class DatabaseCleaner { + + private static final String REFERENTIAL_FORMAT = "set referential_integrity %b;"; + private static final String TRUNCATE_FORMAT = "truncate table %s restart identity;"; + + @PersistenceContext + private EntityManager em; + private String truncateTablesQuery; + + @PostConstruct + public void createTruncateQuery() { + List<String> tableNames = getTableNames(); + StringBuilder stringBuilder = new StringBuilder(); + + for (String tableName : tableNames) { + String truncateQuery = String.format(TRUNCATE_FORMAT, tableName); + stringBuilder.append(truncateQuery); + } + truncateTablesQuery = stringBuilder.toString(); + } + + private List<String> getTableNames() { + String sql = """ + select table_name + from information_schema.tables + where table_schema = 'PUBLIC' + """; + return em.createNativeQuery(sql).getResultList(); + } + + @Transactional + public void clear() { + em.clear(); + truncate(); + } + + private void truncate() { + em.createNativeQuery(String.format(REFERENTIAL_FORMAT, false)).executeUpdate(); + em.createNativeQuery(truncateTablesQuery).executeUpdate(); + em.createNativeQuery(String.format(REFERENTIAL_FORMAT, true)).executeUpdate(); + } +} diff --git a/server/src/test/java/server/haengdong/support/extension/DatabaseCleanerExtension.java b/server/src/test/java/server/haengdong/support/extension/DatabaseCleanerExtension.java new file mode 100644 index 000000000..653ecadb3 --- /dev/null +++ b/server/src/test/java/server/haengdong/support/extension/DatabaseCleanerExtension.java @@ -0,0 +1,19 @@ +package server.haengdong.support.extension; + +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +public class DatabaseCleanerExtension implements AfterEachCallback { + + @Override + public void afterEach(ExtensionContext context) { + DatabaseCleaner databaseCleaner = getDataCleaner(context); + databaseCleaner.clear(); + } + + private DatabaseCleaner getDataCleaner(ExtensionContext extensionContext) { + return SpringExtension.getApplicationContext(extensionContext) + .getBean(DatabaseCleaner.class); + } +} From 7c6f2c4eedb094fb1141c362ab542cb0c2ebfccc Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Wed, 7 Aug 2024 10:47:10 +0900 Subject: [PATCH 119/178] =?UTF-8?q?feat:=20=ED=96=89=EC=82=AC=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=EC=9E=90=20=EB=B9=84=EB=B0=80=EB=B2=88=ED=98=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(#213)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 이벤트 비밀번호 추 * test: 테스트 공통 설정 클래스 분리 * feat: 어드민 인터셉터 추가 및 jwt 설정 추가 * feat: 이벤트 로그인 기능 구현 Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Co-authored-by: khabh <khabh@naver.com> * feat: 쿠키 설정 분리 Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Co-authored-by: khabh <khabh@naver.com> * submodule 업데이트 * style: 주석 제거 Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Co-authored-by: khabh <khabh@naver.com> * refactor: 로컬 환경 쿠키 secure 옵션 제거 Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Co-authored-by: khabh <khabh@naver.com> * test: 접근제어자 수정 Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Co-authored-by: khabh <khabh@naver.com> * test: 개행 추가 Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Co-authored-by: khabh <khabh@naver.com> --------- Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Co-authored-by: khabh <khabh@naver.com> --- server/build.gradle | 8 ++- .../haengdong/application/AuthService.java | 40 ++++++++++++ .../haengdong/application/EventService.java | 26 +++++--- .../application/request/EventAppRequest.java | 4 +- .../request/EventLoginAppRequest.java | 4 ++ .../haengdong/config/AdminInterceptor.java | 44 +++++++++++++ .../server/haengdong/config/WebConfig.java | 27 -------- .../server/haengdong/config/WebMvcConfig.java | 65 +++++++++++++++++++ .../haengdong/domain/TokenProvider.java | 12 ++++ .../server/haengdong/domain/event/Event.java | 20 +++++- .../exception/AuthenticationException.java | 4 ++ .../exception/GlobalExceptionHandler.java | 7 ++ .../exception/HaengdongErrorCode.java | 1 + .../auth/AuthenticationExtractor.java | 22 +++++++ .../infrastructure/auth/CookieProperties.java | 14 ++++ .../infrastructure/auth/JwtTokenProvider.java | 54 +++++++++++++++ .../infrastructure/auth/TokenProperties.java | 7 ++ .../presentation/EventController.java | 40 +++++++++++- .../request/EventLoginRequest.java | 14 ++++ .../request/EventSaveRequest.java | 7 +- server/src/main/resources/application.yml | 19 ++++-- server/src/main/resources/config | 2 +- .../application/ActionServiceTest.java | 13 ++-- .../application/BillActionServiceTest.java | 32 ++++----- .../application/EventServiceTest.java | 36 ++++------ .../application/MemberActionFactoryTest.java | 28 ++++---- .../application/MemberActionServiceTest.java | 29 ++++----- .../application/ServiceTestSupport.java | 11 ++++ .../haengdong/domain/action/ActionTest.java | 5 +- .../domain/action/BillActionTest.java | 7 +- .../domain/action/CurrentMembersTest.java | 9 ++- .../domain/action/MemberBillReportTest.java | 4 +- .../haengdong/domain/event/EventTest.java | 14 +++- .../presentation/ActionControllerTest.java | 15 +---- .../BillActionControllerTest.java | 20 +----- .../presentation/ControllerTestSupport.java | 47 ++++++++++++++ .../presentation/EventControllerTest.java | 41 +++++++----- .../MemberActionControllerTest.java | 18 +---- .../haengdong/support/fixture/Fixture.java | 9 +++ server/src/test/resources/application.yml | 18 ----- 40 files changed, 563 insertions(+), 234 deletions(-) create mode 100644 server/src/main/java/server/haengdong/application/AuthService.java create mode 100644 server/src/main/java/server/haengdong/application/request/EventLoginAppRequest.java create mode 100644 server/src/main/java/server/haengdong/config/AdminInterceptor.java delete mode 100644 server/src/main/java/server/haengdong/config/WebConfig.java create mode 100644 server/src/main/java/server/haengdong/config/WebMvcConfig.java create mode 100644 server/src/main/java/server/haengdong/domain/TokenProvider.java create mode 100644 server/src/main/java/server/haengdong/exception/AuthenticationException.java create mode 100644 server/src/main/java/server/haengdong/infrastructure/auth/AuthenticationExtractor.java create mode 100644 server/src/main/java/server/haengdong/infrastructure/auth/CookieProperties.java create mode 100644 server/src/main/java/server/haengdong/infrastructure/auth/JwtTokenProvider.java create mode 100644 server/src/main/java/server/haengdong/infrastructure/auth/TokenProperties.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/EventLoginRequest.java create mode 100644 server/src/test/java/server/haengdong/application/ServiceTestSupport.java create mode 100644 server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java create mode 100644 server/src/test/java/server/haengdong/support/fixture/Fixture.java delete mode 100644 server/src/test/resources/application.yml diff --git a/server/build.gradle b/server/build.gradle index 526c3640e..9e59b348f 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -28,10 +28,16 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-actuator' + + implementation 'io.jsonwebtoken:jjwt:0.9.1' + implementation 'javax.xml.bind:jaxb-api:2.3.1' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + runtimeOnly 'com.h2database:h2' runtimeOnly 'com.mysql:mysql-connector-j' - annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } diff --git a/server/src/main/java/server/haengdong/application/AuthService.java b/server/src/main/java/server/haengdong/application/AuthService.java new file mode 100644 index 000000000..6a22fcbe2 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/AuthService.java @@ -0,0 +1,40 @@ +package server.haengdong.application; + + +import java.util.Map; +import server.haengdong.domain.TokenProvider; +import server.haengdong.exception.AuthenticationException; + +public class AuthService { + + private static final String TOKEN_NAME = "eventToken"; + private static final String CLAIM_SUB = "sub"; + + private final TokenProvider tokenProvider; + + public AuthService(TokenProvider tokenProvider) { + this.tokenProvider = tokenProvider; + } + + public String createToken(String eventId) { + Map<String, Object> payload = Map.of(CLAIM_SUB, eventId); + + return tokenProvider.createToken(payload); + } + + public String findEventIdByToken(String token) { + validateToken(token); + Map<String, Object> payload = tokenProvider.getPayload(token); + return (String) payload.get(CLAIM_SUB); + } + + private void validateToken(String token) { + if (!tokenProvider.validateToken(token)) { + throw new AuthenticationException(); + } + } + + public String getTokenName() { + return TOKEN_NAME; + } +} diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java index 52080ae8f..01f198571 100644 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -7,6 +7,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.request.EventLoginAppRequest; import server.haengdong.application.request.MemberUpdateAppRequest; import server.haengdong.application.response.ActionAppResponse; import server.haengdong.application.response.EventAppResponse; @@ -19,6 +20,7 @@ import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.domain.event.EventTokenProvider; +import server.haengdong.exception.AuthenticationException; import server.haengdong.exception.HaengdongErrorCode; import server.haengdong.exception.HaengdongException; @@ -42,15 +44,13 @@ public EventAppResponse saveEvent(EventAppRequest request) { } public EventDetailAppResponse findEvent(String token) { - Event event = eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + Event event = getEvent(token); return EventDetailAppResponse.of(event); } public List<ActionAppResponse> findActions(String token) { - Event event = eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + Event event = getEvent(token); List<BillAction> billActions = billActionRepository.findByAction_Event(event).stream() .sorted(Comparator.comparing(BillAction::getSequence)).toList(); @@ -92,8 +92,7 @@ private List<ActionAppResponse> getActionAppResponses( } public MembersAppResponse findAllMembers(String token) { - Event event = eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + Event event = getEvent(token); List<String> memberNames = memberActionRepository.findAllUniqueMemberByEvent(event); @@ -102,8 +101,7 @@ public MembersAppResponse findAllMembers(String token) { @Transactional public void updateMember(String token, String memberName, MemberUpdateAppRequest request) { - Event event = eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + Event event = getEvent(token); String updatedMemberName = request.name(); validateMemberNameUnique(event, updatedMemberName); @@ -117,4 +115,16 @@ private void validateMemberNameUnique(Event event, String updatedMemberName) { throw new HaengdongException(HaengdongErrorCode.DUPLICATED_MEMBER_NAME); } } + + public void validatePassword(EventLoginAppRequest request) throws HaengdongException { + Event event = getEvent(request.token()); + if (event.isSamePassword(request.password())) { + throw new AuthenticationException(); + } + } + + private Event getEvent(String token) { + return eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + } } diff --git a/server/src/main/java/server/haengdong/application/request/EventAppRequest.java b/server/src/main/java/server/haengdong/application/request/EventAppRequest.java index 1eea6adf4..20ec16d88 100644 --- a/server/src/main/java/server/haengdong/application/request/EventAppRequest.java +++ b/server/src/main/java/server/haengdong/application/request/EventAppRequest.java @@ -2,9 +2,9 @@ import server.haengdong.domain.event.Event; -public record EventAppRequest(String name) { +public record EventAppRequest(String name, String password) { public Event toEvent(String token) { - return new Event(name, token); + return new Event(name, password, token); } } diff --git a/server/src/main/java/server/haengdong/application/request/EventLoginAppRequest.java b/server/src/main/java/server/haengdong/application/request/EventLoginAppRequest.java new file mode 100644 index 000000000..947b5ef39 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/EventLoginAppRequest.java @@ -0,0 +1,4 @@ +package server.haengdong.application.request; + +public record EventLoginAppRequest(String token, String password) { +} diff --git a/server/src/main/java/server/haengdong/config/AdminInterceptor.java b/server/src/main/java/server/haengdong/config/AdminInterceptor.java new file mode 100644 index 000000000..e8b9793ed --- /dev/null +++ b/server/src/main/java/server/haengdong/config/AdminInterceptor.java @@ -0,0 +1,44 @@ +package server.haengdong.config; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.servlet.HandlerInterceptor; +import server.haengdong.application.AuthService; +import server.haengdong.exception.AuthenticationException; +import server.haengdong.infrastructure.auth.AuthenticationExtractor; + +@Slf4j +public class AdminInterceptor implements HandlerInterceptor { + + private final AuthService authService; + private final AuthenticationExtractor authenticationExtractor; + + public AdminInterceptor(AuthService authService, AuthenticationExtractor authenticationExtractor) { + this.authService = authService; + this.authenticationExtractor = authenticationExtractor; + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + log.trace("login request = {}", request.getRequestURI()); + + String method = request.getMethod(); + if (method.equals("GET")) { + return true; + } + + validateToken(request); + + return true; + } + + private void validateToken(HttpServletRequest request) { + String token = authenticationExtractor.extract(request, authService.getTokenName()); + String tokenEventId = authService.findEventIdByToken(token); + String eventId = request.getRequestURI().split("/")[2]; + if (!tokenEventId.equals(eventId)) { + throw new AuthenticationException(); + } + } +} diff --git a/server/src/main/java/server/haengdong/config/WebConfig.java b/server/src/main/java/server/haengdong/config/WebConfig.java deleted file mode 100644 index 129d8b790..000000000 --- a/server/src/main/java/server/haengdong/config/WebConfig.java +++ /dev/null @@ -1,27 +0,0 @@ -package server.haengdong.config; - -import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.CorsRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -@RequiredArgsConstructor -@Configuration -public class WebConfig implements WebMvcConfigurer { - - @Value("${cors.max-age}") - private Long maxAge; - - @Value("${cors.allowed-origins}") - private String[] allowedOrigins; - - @Override - public void addCorsMappings(CorsRegistry registry) { - registry.addMapping("/**") - .allowedOrigins(allowedOrigins) - .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS") - .allowedHeaders("*") - .maxAge(maxAge); - } -} diff --git a/server/src/main/java/server/haengdong/config/WebMvcConfig.java b/server/src/main/java/server/haengdong/config/WebMvcConfig.java new file mode 100644 index 000000000..3d2d9f60b --- /dev/null +++ b/server/src/main/java/server/haengdong/config/WebMvcConfig.java @@ -0,0 +1,65 @@ +package server.haengdong.config; + +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import server.haengdong.application.AuthService; +import server.haengdong.domain.TokenProvider; +import server.haengdong.infrastructure.auth.AuthenticationExtractor; +import server.haengdong.infrastructure.auth.JwtTokenProvider; +import server.haengdong.infrastructure.auth.TokenProperties; + +@RequiredArgsConstructor +@EnableConfigurationProperties(TokenProperties.class) +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + + private final TokenProperties tokenProperties; + + @Value("${cors.max-age}") + private Long maxAge; + + @Value("${cors.allowed-origins}") + private String[] allowedOrigins; + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOrigins(allowedOrigins) + .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS") + .allowedHeaders("*") + .maxAge(maxAge); + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(adminInterceptor()) + .addPathPatterns("/api/**") + .excludePathPatterns("/api/events"); + } + + @Bean + public AdminInterceptor adminInterceptor() { + return new AdminInterceptor(authService(), authenticationExtractor()); + } + + @Bean + public AuthService authService() { + return new AuthService(tokenProvider()); + } + + @Bean + public TokenProvider tokenProvider() { + return new JwtTokenProvider(tokenProperties); + } + + @Bean + public AuthenticationExtractor authenticationExtractor() { + return new AuthenticationExtractor(); + } +} diff --git a/server/src/main/java/server/haengdong/domain/TokenProvider.java b/server/src/main/java/server/haengdong/domain/TokenProvider.java new file mode 100644 index 000000000..28e7956c3 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/TokenProvider.java @@ -0,0 +1,12 @@ +package server.haengdong.domain; + +import java.util.Map; + +public interface TokenProvider { + + String createToken(Map<String, Object> payload); + + Map<String, Object> getPayload(String token); + + boolean validateToken(String token); +} diff --git a/server/src/main/java/server/haengdong/domain/event/Event.java b/server/src/main/java/server/haengdong/domain/event/Event.java index 17bffa44d..f43145f0d 100644 --- a/server/src/main/java/server/haengdong/domain/event/Event.java +++ b/server/src/main/java/server/haengdong/domain/event/Event.java @@ -4,6 +4,8 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -18,6 +20,7 @@ public class Event { private static final int MIN_NAME_LENGTH = 2; private static final int MAX_NAME_LENGTH = 20; private static final String SPACES = " "; + private static final Pattern PASSWORD_PATTERN = Pattern.compile("^\\d{4}$"); @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -25,11 +28,15 @@ public class Event { private String name; + private String password; + private String token; - public Event(String name, String token) { + public Event(String name, String password, String token) { validateName(name); + validatePassword(password); this.name = name; + this.password = password; this.token = token; } @@ -48,6 +55,13 @@ private void validateName(String name) { } } + private void validatePassword(String password) { + Matcher matcher = PASSWORD_PATTERN.matcher(password); + if (!matcher.matches()) { + throw new HaengdongException(HaengdongErrorCode.BAD_REQUEST, "비밀번호는 4자리 숫자만 가능합니다."); + } + } + private boolean isBlankContinuous(String name) { return name.contains(SPACES); } @@ -55,4 +69,8 @@ private boolean isBlankContinuous(String name) { public boolean isTokenMismatch(String token) { return !this.token.equals(token); } + + public boolean isSamePassword(String password) { + return this.password.equals(password); + } } diff --git a/server/src/main/java/server/haengdong/exception/AuthenticationException.java b/server/src/main/java/server/haengdong/exception/AuthenticationException.java new file mode 100644 index 000000000..78a16e295 --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/AuthenticationException.java @@ -0,0 +1,4 @@ +package server.haengdong.exception; + +public class AuthenticationException extends RuntimeException { +} diff --git a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java index fb15afc56..e45f2da67 100644 --- a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java +++ b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java @@ -2,6 +2,7 @@ import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.web.HttpRequestMethodNotSupportedException; @@ -14,6 +15,12 @@ @RestControllerAdvice public class GlobalExceptionHandler { + @ExceptionHandler(AuthenticationException.class) + public ResponseEntity<ErrorResponse> authenticationException() { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED) + .body(ErrorResponse.of(HaengdongErrorCode.UNAUTHORIZED)); + } + @ExceptionHandler({HttpRequestMethodNotSupportedException.class, NoResourceFoundException.class}) public ResponseEntity<ErrorResponse> noResourceException() { return ResponseEntity.badRequest() diff --git a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java index c9f461c5f..93667d052 100644 --- a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java +++ b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java @@ -7,6 +7,7 @@ public enum HaengdongErrorCode { BAD_REQUEST("R_001", "잘못된 요청입니다."), NO_RESOURCE_REQUEST("R_002", "잘못된 엔드포인트입니다."), MESSAGE_NOT_READABLE("R_003", "읽을 수 없는 요청 형식입니다."), + UNAUTHORIZED("A_001", "인증에 실패했습니다."), INTERNAL_SERVER_ERROR("S_001", "서버 내부에서 에러가 발생했습니다."), DUPLICATED_MEMBER_NAME("EV_001", "중복된 행사 참여 인원 이름이 존재합니다."), NOT_FOUND_EVENT("EV_400", "존재하지 않는 행사입니다."), diff --git a/server/src/main/java/server/haengdong/infrastructure/auth/AuthenticationExtractor.java b/server/src/main/java/server/haengdong/infrastructure/auth/AuthenticationExtractor.java new file mode 100644 index 000000000..74489577d --- /dev/null +++ b/server/src/main/java/server/haengdong/infrastructure/auth/AuthenticationExtractor.java @@ -0,0 +1,22 @@ +package server.haengdong.infrastructure.auth; + +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import java.util.Arrays; +import server.haengdong.exception.AuthenticationException; + +public class AuthenticationExtractor { + + public String extract(HttpServletRequest request, String cookieName) { + Cookie[] cookies = request.getCookies(); + if (cookies == null) { + throw new AuthenticationException(); + } + + return Arrays.stream(cookies) + .filter(cookie -> cookieName.equals(cookie.getName())) + .findFirst() + .orElseThrow(AuthenticationException::new) + .getValue(); + } +} diff --git a/server/src/main/java/server/haengdong/infrastructure/auth/CookieProperties.java b/server/src/main/java/server/haengdong/infrastructure/auth/CookieProperties.java new file mode 100644 index 000000000..40d4252fd --- /dev/null +++ b/server/src/main/java/server/haengdong/infrastructure/auth/CookieProperties.java @@ -0,0 +1,14 @@ +package server.haengdong.infrastructure.auth; + +import java.time.Duration; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties("cookie") +public record CookieProperties( + boolean httpOnly, + boolean secure, + String domain, + String path, + Duration maxAge +) { +} diff --git a/server/src/main/java/server/haengdong/infrastructure/auth/JwtTokenProvider.java b/server/src/main/java/server/haengdong/infrastructure/auth/JwtTokenProvider.java new file mode 100644 index 000000000..df9ec6a81 --- /dev/null +++ b/server/src/main/java/server/haengdong/infrastructure/auth/JwtTokenProvider.java @@ -0,0 +1,54 @@ +package server.haengdong.infrastructure.auth; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jws; +import io.jsonwebtoken.JwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import server.haengdong.domain.TokenProvider; + +public class JwtTokenProvider implements TokenProvider { + + private final TokenProperties tokenProperties; + + public JwtTokenProvider(TokenProperties tokenProperties) { + this.tokenProperties = tokenProperties; + } + + @Override + public String createToken(Map<String, Object> payload) { + Claims claims = Jwts.claims(new HashMap<>(payload)); + Date now = new Date(); + Date validity = new Date(now.getTime() + tokenProperties.expireLength()); + + return Jwts.builder() + .setClaims(claims) + .setIssuedAt(now) + .setExpiration(validity) + .signWith(SignatureAlgorithm.HS256, tokenProperties.secretKey()) + .compact(); + } + + @Override + public Map<String, Object> getPayload(String token) { + return Jwts.parser() + .setSigningKey(tokenProperties.secretKey()) + .parseClaimsJws(token) + .getBody(); + } + + @Override + public boolean validateToken(String token) { + try { + Jws<Claims> claims = Jwts.parser().setSigningKey(tokenProperties.secretKey()).parseClaimsJws(token); + + return !claims.getBody().getExpiration().before(new Date()); + } catch (JwtException | IllegalArgumentException e) { + return false; + } + } +} + diff --git a/server/src/main/java/server/haengdong/infrastructure/auth/TokenProperties.java b/server/src/main/java/server/haengdong/infrastructure/auth/TokenProperties.java new file mode 100644 index 000000000..11dedcdbf --- /dev/null +++ b/server/src/main/java/server/haengdong/infrastructure/auth/TokenProperties.java @@ -0,0 +1,7 @@ +package server.haengdong.infrastructure.auth; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties("security.jwt.token") +public record TokenProperties(String secretKey, Long expireLength) { +} diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java index b6be87911..3a6ce5b97 100644 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -2,6 +2,9 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -9,7 +12,10 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.AuthService; import server.haengdong.application.EventService; +import server.haengdong.infrastructure.auth.CookieProperties; +import server.haengdong.presentation.request.EventLoginRequest; import server.haengdong.presentation.request.EventSaveRequest; import server.haengdong.presentation.request.MemberUpdateRequest; import server.haengdong.presentation.response.EventDetailResponse; @@ -18,16 +24,24 @@ import server.haengdong.presentation.response.StepsResponse; @RequiredArgsConstructor +@EnableConfigurationProperties(CookieProperties.class) @RestController public class EventController { private final EventService eventService; + private final AuthService authService; + private final CookieProperties cookieProperties; @PostMapping("/api/events") public ResponseEntity<EventResponse> saveEvent(@Valid @RequestBody EventSaveRequest request) { EventResponse eventResponse = EventResponse.of(eventService.saveEvent(request.toAppRequest())); - return ResponseEntity.ok(eventResponse); + String jwtToken = authService.createToken(eventResponse.eventId()); + + ResponseCookie responseCookie = createResponseCookie(jwtToken); + return ResponseEntity.ok() + .header(HttpHeaders.SET_COOKIE, responseCookie.toString()) + .body(eventResponse); } @GetMapping("/api/events/{eventId}") @@ -61,4 +75,28 @@ public ResponseEntity<Void> updateMember( return ResponseEntity.ok().build(); } + + @PostMapping("/api/events/{eventId}/login") + public ResponseEntity<Void> loginEvent( + @PathVariable("eventId") String token, + @Valid @RequestBody EventLoginRequest request + ) { + eventService.validatePassword(request.toAppRequest(token)); + String jwtToken = authService.createToken(token); + + ResponseCookie responseCookie = createResponseCookie(jwtToken); + return ResponseEntity.ok() + .header(HttpHeaders.SET_COOKIE, responseCookie.toString()) + .build(); + } + + private ResponseCookie createResponseCookie(String token) { + return ResponseCookie.from(authService.getTokenName(), token) + .httpOnly(cookieProperties.httpOnly()) + .secure(cookieProperties.secure()) + .domain(cookieProperties.domain()) + .path(cookieProperties.path()) + .maxAge(cookieProperties.maxAge()) + .build(); + } } diff --git a/server/src/main/java/server/haengdong/presentation/request/EventLoginRequest.java b/server/src/main/java/server/haengdong/presentation/request/EventLoginRequest.java new file mode 100644 index 000000000..d1e743821 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/EventLoginRequest.java @@ -0,0 +1,14 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import server.haengdong.application.request.EventLoginAppRequest; + +public record EventLoginRequest( + + @NotBlank + String password +) { + public EventLoginAppRequest toAppRequest(String token) { + return new EventLoginAppRequest(token, password); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java index b28572332..fb9683916 100644 --- a/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java @@ -6,10 +6,13 @@ public record EventSaveRequest( @NotBlank - String eventName + String eventName, + + @NotBlank + String password ) { public EventAppRequest toAppRequest() { - return new EventAppRequest(eventName); + return new EventAppRequest(eventName, password); } } diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index c0099e93e..e3465c9ad 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -22,6 +22,18 @@ cors: max-age: 3600 allowed-origins: http://localhost:3000, https://haengdong.pro, https://dev.haengdong.pro, https://app.haengdong.pro +security: + jwt: + token: + secret-key: skdmeejEKJdkDjklDlkj123DKLJ3kDkeDkDKQMEOD1D90D8dE + expire-length: 604800 # 1주일 + +cookie: + http-only: true + secure: false + path: / + max-age: 7D + management: endpoints: web: @@ -30,15 +42,10 @@ management: logging: level: - root: info + root: debug org.springframework.web: debug server.haengdong: debug - file: - name: logs/spring-boot-application.log - path: logs - config: classpath:logback-spring.xml - --- spring: diff --git a/server/src/main/resources/config b/server/src/main/resources/config index c946d00b8..9129bc475 160000 --- a/server/src/main/resources/config +++ b/server/src/main/resources/config @@ -1 +1 @@ -Subproject commit c946d00b8f35ee39446f780cc2cf3983461cd38c +Subproject commit 9129bc4756c577a511f7372d6ee7dca6b1925b23 diff --git a/server/src/test/java/server/haengdong/application/ActionServiceTest.java b/server/src/test/java/server/haengdong/application/ActionServiceTest.java index 159bdd68e..ad6c60aa9 100644 --- a/server/src/test/java/server/haengdong/application/ActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/ActionServiceTest.java @@ -9,9 +9,7 @@ import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; import server.haengdong.application.response.MemberBillReportAppResponse; import server.haengdong.domain.action.Action; import server.haengdong.domain.action.BillAction; @@ -22,11 +20,9 @@ import server.haengdong.domain.event.EventRepository; import server.haengdong.exception.HaengdongErrorCode; import server.haengdong.exception.HaengdongException; -import server.haengdong.support.extension.DatabaseCleanerExtension; +import server.haengdong.support.fixture.Fixture; -@ExtendWith(DatabaseCleanerExtension.class) -@SpringBootTest -class ActionServiceTest { +class ActionServiceTest extends ServiceTestSupport { @Autowired private ActionService actionService; @@ -43,8 +39,7 @@ class ActionServiceTest { @DisplayName("참여자별 정산 현황을 조회한다.") @Test void getMemberBillReports() { - String token = "tOkEn1"; - Event event = new Event("행동대장", token); + Event event = Fixture.EVENT1; Event savedEvent = eventRepository.save(event); List<MemberAction> memberActions = List.of( new MemberAction(new Action(savedEvent, 1L), "소하", IN, 1L), @@ -60,7 +55,7 @@ void getMemberBillReports() { memberActionRepository.saveAll(memberActions); billActionRepository.saveAll(billActions); - List<MemberBillReportAppResponse> responses = actionService.getMemberBillReports(token); + List<MemberBillReportAppResponse> responses = actionService.getMemberBillReports(event.getToken()); assertThat(responses) .hasSize(3) diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java index 76b576542..51eaa6e0b 100644 --- a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java @@ -8,23 +8,18 @@ import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; import server.haengdong.application.request.BillActionAppRequest; import server.haengdong.application.request.BillActionUpdateAppRequest; import server.haengdong.domain.action.Action; -import server.haengdong.domain.action.ActionRepository; import server.haengdong.domain.action.BillAction; import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.exception.HaengdongException; -import server.haengdong.support.extension.DatabaseCleanerExtension; +import server.haengdong.support.fixture.Fixture; -@ExtendWith(DatabaseCleanerExtension.class) -@SpringBootTest -class BillActionServiceTest { +class BillActionServiceTest extends ServiceTestSupport { @Autowired private BillActionService billActionService; @@ -38,8 +33,7 @@ class BillActionServiceTest { @DisplayName("지출 내역을 생성한다.") @Test void saveAllBillAction() { - String token = "TOKEN2"; - Event event = new Event("감자", token); + Event event = Fixture.EVENT1; Event savedEvent = eventRepository.save(event); List<BillActionAppRequest> requests = List.of( @@ -47,7 +41,7 @@ void saveAllBillAction() { new BillActionAppRequest("인생맥주", 15_000L) ); - billActionService.saveAllBillAction(token, requests); + billActionService.saveAllBillAction(event.getToken(), requests); List<BillAction> actions = billActionRepository.findByAction_Event(savedEvent); @@ -73,8 +67,7 @@ void saveAllBillAction1() { @DisplayName("지출 액션을 수정한다.") @Test void updateBillAction() { - String token = "TOKEN"; - Event event = new Event("감자", token); + Event event = Fixture.EVENT1; Event savedEvent = eventRepository.save(event); Action action = Action.createFirst(savedEvent); BillAction billAction = new BillAction(action, "뽕족", 10_000L); @@ -83,7 +76,7 @@ void updateBillAction() { Long actionId = savedBillAction.getAction().getId(); BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L); - billActionService.updateBillAction(token, actionId, request); + billActionService.updateBillAction(event.getToken(), actionId, request); BillAction updatedBillAction = billActionRepository.findById(savedBillAction.getId()).get(); @@ -96,10 +89,8 @@ void updateBillAction() { @DisplayName("행사에 속하지 않은 지출 액션은 수정할 수 없다.") @Test void updateBillAction1() { - String token1 = "쿠키 토큰"; - String token2 = "웨디 토큰"; - Event event1 = new Event("감자1", token1); - Event event2 = new Event("감자2", token2); + Event event1 = Fixture.EVENT1; + Event event2 = Fixture.EVENT2; Event savedEvent1 = eventRepository.save(event1); Event savedEvent2 = eventRepository.save(event2); Action action1 = Action.createFirst(savedEvent1); @@ -112,21 +103,20 @@ void updateBillAction1() { Long actionId = savedBillAction1.getAction().getId(); BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L); - assertThatThrownBy(() -> billActionService.updateBillAction(token2, actionId, request)) + assertThatThrownBy(() -> billActionService.updateBillAction(event2.getToken(), actionId, request)) .isInstanceOf(HaengdongException.class); } @DisplayName("지출 내역을 삭제한다.") @Test void deleteBillAction() { - String token = "토다리 토큰"; - Event event = new Event("감자", token); + Event event = Fixture.EVENT1; eventRepository.save(event); BillAction billAction = new BillAction(new Action(event, 1L), "커피", 50_900L); billActionRepository.save(billAction); Long actionId = billAction.getAction().getId(); - billActionService.deleteBillAction(token, actionId); + billActionService.deleteBillAction(event.getToken(), actionId); assertThat(billActionRepository.findById(billAction.getId())).isEmpty(); } diff --git a/server/src/test/java/server/haengdong/application/EventServiceTest.java b/server/src/test/java/server/haengdong/application/EventServiceTest.java index bf85d1bc3..f5694efa1 100644 --- a/server/src/test/java/server/haengdong/application/EventServiceTest.java +++ b/server/src/test/java/server/haengdong/application/EventServiceTest.java @@ -11,9 +11,7 @@ import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import server.haengdong.application.request.EventAppRequest; import server.haengdong.application.request.MemberUpdateAppRequest; @@ -29,12 +27,10 @@ import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.domain.event.EventTokenProvider; -import server.haengdong.support.extension.DatabaseCleanerExtension; import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; -@ExtendWith(DatabaseCleanerExtension.class) -@SpringBootTest -class EventServiceTest { +class EventServiceTest extends ServiceTestSupport { @Autowired private EventService eventService; @@ -54,7 +50,7 @@ class EventServiceTest { @DisplayName("행사를 생성한다") @Test void saveEventTest() { - EventAppRequest request = new EventAppRequest("test"); + EventAppRequest request = new EventAppRequest("test", "1234"); given(eventTokenProvider.createToken()).willReturn("TOKEN"); EventAppResponse response = eventService.saveEvent(request); @@ -65,19 +61,18 @@ void saveEventTest() { @DisplayName("토큰으로 행사를 조회한다.") @Test void findEventTest() { - String token = "TOKEN"; - Event event = new Event("행동대장 회식", token); + Event event = Fixture.EVENT1; eventRepository.save(event); - EventDetailAppResponse eventDetailAppResponse = eventService.findEvent(token); + EventDetailAppResponse eventDetailAppResponse = eventService.findEvent(event.getToken()); - assertThat(eventDetailAppResponse.eventName()).isEqualTo("행동대장 회식"); + assertThat(eventDetailAppResponse.eventName()).isEqualTo(event.getName()); } @DisplayName("행사에 속한 모든 액션을 조회한다.") @Test void findActionsTest() { - Event event = new Event("행동대장 회식", "웨디_토큰"); + Event event = Fixture.EVENT1; Action action = new Action(event, 1L); MemberAction memberAction = new MemberAction(action, "토다리", IN, 1L); Action action1 = new Action(event, 2L); @@ -88,7 +83,7 @@ void findActionsTest() { memberActionRepository.saveAll(List.of(memberAction, memberAction1)); billActionRepository.save(billAction); - List<ActionAppResponse> actionAppResponses = eventService.findActions("웨디_토큰"); + List<ActionAppResponse> actionAppResponses = eventService.findActions(event.getToken()); assertThat(actionAppResponses).hasSize(3) .extracting(ActionAppResponse::actionId, @@ -106,8 +101,7 @@ void findActionsTest() { @DisplayName("행사에 참여한 전체 인원을 중복 없이 조회한다.") @Test void findAllMembersTest() { - String token = "웨디_토큰"; - Event event = new Event("행동대장 회식", token); + Event event = Fixture.EVENT1; Action action1 = new Action(event, 1L); Action action2 = new Action(event, 2L); Action action3 = new Action(event, 3L); @@ -120,7 +114,7 @@ void findAllMembersTest() { billActionRepository.save(billAction); memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); - MembersAppResponse membersAppResponse = eventService.findAllMembers(token); + MembersAppResponse membersAppResponse = eventService.findAllMembers(event.getToken()); assertThat(membersAppResponse.memberNames()).containsExactlyInAnyOrder("토다리", "쿠키"); } @@ -128,8 +122,7 @@ void findAllMembersTest() { @DisplayName("행사 참여 인원의 이름을 변경한다.") @Test void updateMember() { - String token = "행동대장 회식"; - Event event = new Event("행동대장 회식", token); + Event event = Fixture.EVENT1; MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "토다리", IN, 1L); MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "쿠키", IN, 1L); MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "웨디", IN, 2L); @@ -141,7 +134,7 @@ void updateMember() { memberAction1, memberAction2, memberAction3, memberAction4, memberAction5, memberAction6 )); - eventService.updateMember(token, "쿠키", new MemberUpdateAppRequest("쿡쿡")); + eventService.updateMember(event.getToken(), "쿠키", new MemberUpdateAppRequest("쿡쿡")); List<MemberAction> foundMemberActions = memberActionRepository.findAllByEvent(event); assertThat(foundMemberActions) @@ -159,15 +152,14 @@ void updateMember() { @DisplayName("참여 인원 이름을 이미 존재하는 행사 참여 인원과 동일한 이름으로 변경할 수 없다.") @Test void updateMember1() { - String token = "행동대장 회식"; - Event event = new Event("행동대장 회식", token); + Event event = Fixture.EVENT1; MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "토다리", IN, 1L); MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "쿠키", IN, 1L); MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "웨디", IN, 2L); eventRepository.save(event); memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); - assertThatThrownBy(() -> eventService.updateMember(token, "쿠키", new MemberUpdateAppRequest("토다리"))) + assertThatThrownBy(() -> eventService.updateMember(event.getToken(), "쿠키", new MemberUpdateAppRequest("토다리"))) .isInstanceOf(HaengdongException.class); } } diff --git a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java index 2c2a978ae..c04f06026 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java @@ -8,9 +8,7 @@ import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; import server.haengdong.application.request.MemberActionSaveAppRequest; import server.haengdong.application.request.MemberActionsSaveAppRequest; import server.haengdong.domain.action.Action; @@ -21,11 +19,9 @@ import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.exception.HaengdongException; -import server.haengdong.support.extension.DatabaseCleanerExtension; +import server.haengdong.support.fixture.Fixture; -@ExtendWith(DatabaseCleanerExtension.class) -@SpringBootTest -class MemberActionFactoryTest { +class MemberActionFactoryTest extends ServiceTestSupport { @Autowired private MemberActionFactory memberActionFactory; @@ -39,7 +35,7 @@ class MemberActionFactoryTest { @DisplayName("이전 멤버 액션이 시퀀스 기준으로 정렬되지 않은 상태에서 새로운 멤버 액션 요청을 검증한다.") @Test void createMemberActionsTest() { - Event event = eventRepository.save(new Event("우당탕탕 행동대장 백엔드 회식", "토다리_토큰")); + Event event = eventRepository.save(Fixture.EVENT1); Action action1 = new Action(event, 1L); Action action2 = new Action(event, 2L); MemberAction memberAction1 = new MemberAction(action1, "토다리", MemberActionStatus.IN, 1L); @@ -60,7 +56,7 @@ void createMemberActionsTest() { @DisplayName("인원 변동 액션을 생성한다.") @Test void createMemberActionsTest1() { - Event event = eventRepository.save(new Event("우당탕탕 행동대장 백엔드 회식", "토다리_토큰")); + Event event = eventRepository.save(Fixture.EVENT1); Action action = new Action(event, 1L); MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); memberActionRepository.save(memberAction); @@ -84,7 +80,7 @@ void createMemberActionsTest1() { @DisplayName("현재 행사에 참여 중인 경우에 퇴장할 수 있다.") @Test void createMemberActionsTest2() { - Event event = eventRepository.save(new Event("test", "TOKEN")); + Event event = eventRepository.save(Fixture.EVENT1); Action action = new Action(event, 1L); MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); memberActionRepository.save(memberAction); @@ -101,7 +97,7 @@ void createMemberActionsTest2() { @DisplayName("행사에서 퇴장한 경우에 입장할 수 있다.") @Test void createMemberActionsTest3() { - Event event = eventRepository.save(new Event("test", "TOKEN")); + Event event = eventRepository.save(Fixture.EVENT1); Action action1 = new Action(event, 1L); MemberAction memberAction1 = new MemberAction(action1, "토다리", MemberActionStatus.IN, 1L); memberActionRepository.save(memberAction1); @@ -121,7 +117,7 @@ void createMemberActionsTest3() { @DisplayName("행사에 입장한 적 없는 경우에 입장할 수 있다.") @Test void createMemberActionsTest4() { - Event event = eventRepository.save(new Event("test", "TOKEN")); + Event event = eventRepository.save(Fixture.EVENT1); Action action = new Action(event, 1L); MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); memberActionRepository.save(memberAction); @@ -138,7 +134,7 @@ void createMemberActionsTest4() { @DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다.") @Test void createMemberActionTest5() { - Event event = eventRepository.save(new Event("test", "TOKEN")); + Event event = eventRepository.save(Fixture.EVENT1); MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( List.of(new MemberActionSaveAppRequest("쿠키", "OUT"))); @@ -153,7 +149,7 @@ void createMemberActionTest5() { @DisplayName("행사에 이미 참여 중인 경우 다시 입장할 수 없다.") @Test void createMemberActionTest6() { - Event event = eventRepository.save(new Event("test", "TOKEN")); + Event event = eventRepository.save(Fixture.EVENT1); Action action = new Action(event, 1L); MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); memberActionRepository.save(memberAction); @@ -170,7 +166,7 @@ void createMemberActionTest6() { @DisplayName("한 명의 사용자는 동시에 여러 번 입장할 수 없다.") @Test void createMemberActionTest7() { - Event event = eventRepository.save(new Event("test", "TOKEN")); + Event event = eventRepository.save(Fixture.EVENT1); MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( List.of( @@ -188,7 +184,7 @@ void createMemberActionTest7() { @DisplayName("한 명의 사용자는 동시에 여러 번 퇴장할 수 없다.") @Test void createMemberActionTest8() { - Event event = eventRepository.save(new Event("test", "TOKEN")); + Event event = eventRepository.save(Fixture.EVENT1); Action action = new Action(event, 1L); MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); memberActionRepository.save(memberAction); @@ -208,7 +204,7 @@ void createMemberActionTest8() { @DisplayName("한 명의 사용자는 입장과 퇴장을 동시에 할 수 없다.") @Test void createMemberActionTest9() { - Event event = eventRepository.save(new Event("test", "TOKEN")); + Event event = eventRepository.save(Fixture.EVENT1); Action action = new Action(event, 1L); MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); memberActionRepository.save(memberAction); diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java index 5bc9fd1ea..8f0af8dfe 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java @@ -10,9 +10,7 @@ import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; import server.haengdong.application.request.MemberActionSaveAppRequest; import server.haengdong.application.request.MemberActionsSaveAppRequest; import server.haengdong.domain.action.Action; @@ -22,11 +20,9 @@ import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.exception.HaengdongException; -import server.haengdong.support.extension.DatabaseCleanerExtension; +import server.haengdong.support.fixture.Fixture; -@ExtendWith(DatabaseCleanerExtension.class) -@SpringBootTest -class MemberActionServiceTest { +class MemberActionServiceTest extends ServiceTestSupport { @Autowired private MemberActionService memberActionService; @@ -40,12 +36,12 @@ class MemberActionServiceTest { @DisplayName("현재 행사에 참여하고 있는 경우에 나갈 수 있다.") @Test void saveMemberActionTest() { - Event event = eventRepository.save(new Event("test", "TOKEN")); + Event event = eventRepository.save(Fixture.EVENT1); Action action = new Action(event, 1L); MemberAction memberAction = new MemberAction(action, "망쵸", IN, 1L); memberActionRepository.save(memberAction); - assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionsSaveAppRequest( + assertThatCode(() -> memberActionService.saveMemberAction(event.getToken(), new MemberActionsSaveAppRequest( List.of(new MemberActionSaveAppRequest("망쵸", "OUT"))))) .doesNotThrowAnyException(); } @@ -53,7 +49,7 @@ void saveMemberActionTest() { @DisplayName("행사에서 퇴장한 경우에 입장할 수 있다.") @Test void saveMemberActionTest1() { - Event event = eventRepository.save(new Event("test", "TOKEN")); + Event event = eventRepository.save(Fixture.EVENT1); Action actionOne = new Action(event, 1L); MemberAction memberActionOne = new MemberAction(actionOne, "망쵸", IN, 1L); memberActionRepository.save(memberActionOne); @@ -62,7 +58,7 @@ void saveMemberActionTest1() { MemberAction memberActionTwo = new MemberAction(actionTwo, "망쵸", OUT, 1L); memberActionRepository.save(memberActionTwo); - assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", new MemberActionsSaveAppRequest( + assertThatCode(() -> memberActionService.saveMemberAction(event.getToken(), new MemberActionsSaveAppRequest( List.of(new MemberActionSaveAppRequest("망쵸", "IN"))))) .doesNotThrowAnyException(); } @@ -87,8 +83,7 @@ void getCurrentMembers() { @DisplayName("행사의 전체 참여자 중에서 특정 참여자의 맴버 액션을 전부 삭제한다.") @Test void deleteMember() { - String token = "TOKEN"; - Event event = new Event("행동대장 회식", token); + Event event = Fixture.EVENT1; eventRepository.save(event); MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "참여자", IN, 1L); MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "토다리", IN, 1L); @@ -99,14 +94,13 @@ void deleteMember() { memberActionRepository.saveAll( List.of(memberAction1, memberAction2, memberAction3, memberAction4, memberAction5, memberAction6)); - String token2 = "TOKEN2"; - Event event2 = new Event("옆동네 회식", token2); + Event event2 = Fixture.EVENT2; eventRepository.save(event2); Action action2 = Action.createFirst(event2); MemberAction anotherMemberAction = new MemberAction(action2, "참여자", IN, 1L); memberActionRepository.save(anotherMemberAction); - memberActionService.deleteMember(token, "참여자"); + memberActionService.deleteMember(event.getToken(), "참여자"); List<MemberAction> memberActions = memberActionRepository.findAll(); @@ -124,8 +118,7 @@ void deleteMember() { @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") @Test void deleteMemberAction() { - String token = "TOKEN"; - Event event = new Event("행동대장 회식", token); + Event event = Fixture.EVENT1; eventRepository.save(event); MemberAction memberAction1 = createMemberAction(new Action(event, 1L), "토다리", IN, 1L); Action targetAction = new Action(event, 2L); @@ -145,7 +138,7 @@ void deleteMemberAction() { memberAction7) ); - memberActionService.deleteMemberAction(token, targetAction.getId()); + memberActionService.deleteMemberAction(event.getToken(), targetAction.getId()); List<MemberAction> memberActions = memberActionRepository.findAll(); assertThat(memberActions).hasSize(4) diff --git a/server/src/test/java/server/haengdong/application/ServiceTestSupport.java b/server/src/test/java/server/haengdong/application/ServiceTestSupport.java new file mode 100644 index 000000000..b0e2db0a6 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/ServiceTestSupport.java @@ -0,0 +1,11 @@ +package server.haengdong.application; + +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import server.haengdong.support.extension.DatabaseCleanerExtension; + +@ExtendWith(DatabaseCleanerExtension.class) +@SpringBootTest(webEnvironment= WebEnvironment.NONE) +abstract class ServiceTestSupport { +} diff --git a/server/src/test/java/server/haengdong/domain/action/ActionTest.java b/server/src/test/java/server/haengdong/domain/action/ActionTest.java index 199a4f628..6ff25479c 100644 --- a/server/src/test/java/server/haengdong/domain/action/ActionTest.java +++ b/server/src/test/java/server/haengdong/domain/action/ActionTest.java @@ -5,13 +5,14 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import server.haengdong.domain.event.Event; +import server.haengdong.support.fixture.Fixture; class ActionTest { @DisplayName("액션의 초기 순서번호는 1이다.") @Test void createFirst() { - Event event = new Event("name", "token"); + Event event = Fixture.EVENT1; Action action = Action.createFirst(event); assertThat(action.getSequence()).isOne(); @@ -20,7 +21,7 @@ void createFirst() { @DisplayName("현재 액션의 다음 액션의 순서는 1만큼 증가한다.") @Test void next() { - Event event = new Event("name", "token"); + Event event = Fixture.EVENT1; Action action = new Action(event, 2L); Action nextAction = action.next(); diff --git a/server/src/test/java/server/haengdong/domain/action/BillActionTest.java b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java index 601ca95d7..851ed14d9 100644 --- a/server/src/test/java/server/haengdong/domain/action/BillActionTest.java +++ b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java @@ -10,6 +10,7 @@ import org.junit.jupiter.params.provider.ValueSource; import server.haengdong.domain.event.Event; import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; class BillActionTest { @@ -17,7 +18,7 @@ class BillActionTest { @ParameterizedTest @ValueSource(strings = {" 감 ", "", " ", "1234567890123456789012345678901"}) void validateTitle(String title) { - Event event = new Event("name", "token"); + Event event = Fixture.EVENT1; Action action = new Action(event, 1L); Long price = 100L; @@ -30,7 +31,7 @@ void validateTitle(String title) { @ParameterizedTest @ValueSource(longs = {0, 10_000_001, 20_000_000}) void validatePrice(long price) { - Event event = new Event("name", "token"); + Event event = Fixture.EVENT1; Action action = new Action(event, 1L); String title = "title"; @@ -42,7 +43,7 @@ void validatePrice(long price) { @DisplayName("지출 내역을 올바르게 생성한다.") @Test void createBillAction() { - Event event = new Event("name", "token"); + Event event = Fixture.EVENT1; Action action = new Action(event, 1L); String title = "title"; Long price = 1_000L; diff --git a/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java b/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java index 3ed02ddc5..93148abd3 100644 --- a/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java +++ b/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java @@ -9,17 +9,16 @@ import java.util.Set; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import server.haengdong.application.request.MemberActionSaveAppRequest; -import server.haengdong.application.request.MemberActionsSaveAppRequest; import server.haengdong.domain.event.Event; import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; class CurrentMembersTest { @DisplayName("인원 변동 이력으로 현재 참여 인원을 계산한다.") @Test void of() { - Event event = new Event("test", "TOKEN"); + Event event = Fixture.EVENT1; List<MemberAction> memberActions = List.of( new MemberAction(new Action(event, 1L), "망쵸", IN, 1L), new MemberAction(new Action(event, 2L), "백호", IN, 1L), @@ -37,7 +36,7 @@ void of() { @Test void addMemberAction1() { CurrentMembers currentMembers = new CurrentMembers(); - Event event = new Event("이벤트", "token"); + Event event = Fixture.EVENT1; MemberAction memberAction = new MemberAction(new Action(event, 1L), "웨디", IN, 1L); CurrentMembers addedCurrentMembers = currentMembers.addMemberAction(memberAction); @@ -50,7 +49,7 @@ void addMemberAction1() { @DisplayName("인원 변동 액션의 상태가 OUT이면 현재 인원에서 제외한다.") @Test void addMemberAction2() { - Event event = new Event("이벤트", "token"); + Event event = Fixture.EVENT1; MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "웨디", IN, 1L); CurrentMembers currentMembers = new CurrentMembers().addMemberAction(memberAction1); MemberAction memberAction2 = new MemberAction(new Action(event, 1L), "웨디", OUT, 1L); diff --git a/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java b/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java index 9ad27d5bc..197768a0e 100644 --- a/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java +++ b/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java @@ -9,14 +9,14 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import server.haengdong.domain.event.Event; +import server.haengdong.support.fixture.Fixture; class MemberBillReportTest { @DisplayName("액션 목록으로 참가자 정산 리포트를 생성한다.") @Test void createByActions() { - String token = "TOK2N"; - Event event = new Event("행동대장", token); + Event event = Fixture.EVENT1; List<BillAction> billActions = List.of( new BillAction(new Action(event, 4L), "뽕족", 60_000L), new BillAction(new Action(event, 6L), "인생맥주", 40_000L), diff --git a/server/src/test/java/server/haengdong/domain/event/EventTest.java b/server/src/test/java/server/haengdong/domain/event/EventTest.java index 98f6c7050..0d5b58519 100644 --- a/server/src/test/java/server/haengdong/domain/event/EventTest.java +++ b/server/src/test/java/server/haengdong/domain/event/EventTest.java @@ -13,7 +13,7 @@ class EventTest { @ParameterizedTest @ValueSource(strings = {"12", "12345678901234567890", "공 백", " 공백", "공백 ", " 공 백 "}) void createSuccessTest(String eventName) { - assertThatCode(() -> new Event(eventName, "TEST_TOKEN")) + assertThatCode(() -> new Event(eventName, "1234", "TEST_TOKEN")) .doesNotThrowAnyException(); } @@ -21,7 +21,7 @@ void createSuccessTest(String eventName) { @ParameterizedTest @ValueSource(strings = {" 공백", "공백 ", "공백 연속", "공 백"}) void createFailTest1(String eventName) { - assertThatCode(() -> new Event(eventName, "TEST_TOKEN")) + assertThatCode(() -> new Event(eventName, "1234", "TEST_TOKEN")) .isInstanceOf(HaengdongException.class) .hasMessage(String.format("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s", eventName)); } @@ -30,8 +30,16 @@ void createFailTest1(String eventName) { @ParameterizedTest @ValueSource(strings = {"", " ", "123456789012345678901"}) void createFilTest2(String eventName) { - assertThatCode(() -> new Event(eventName, "TEST_TOKEN")) + assertThatCode(() -> new Event(eventName, "1234", "TEST_TOKEN")) .isInstanceOf(HaengdongException.class) .hasMessage(String.format("행사 이름은 2자 이상 20자 이하만 입력 가능합니다. 입력한 이름 길이 : %d", eventName.length())); } + + @DisplayName("비밀번호는 4자리 숫자 입니다.") + @ParameterizedTest + @ValueSource(strings = {"1", "12", "123", "12345", "adgd"}) + void validatePassword(String password) { + assertThatCode(() -> new Event("이름", password, "TEST_TOKEN")) + .isInstanceOf(HaengdongException.class); + } } diff --git a/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java index ce1345917..1de5889b5 100644 --- a/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java @@ -10,23 +10,11 @@ import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; -import server.haengdong.application.ActionService; import server.haengdong.application.response.MemberBillReportAppResponse; -@WebMvcTest(ActionController.class) -class ActionControllerTest { - - @Autowired - private MockMvc mockMvc; - - @MockBean - private ActionService actionService; +class ActionControllerTest extends ControllerTestSupport { @DisplayName("참여자별 정산 현황을 조회한다.") @Test @@ -44,6 +32,5 @@ void getMemberBillReports() throws Exception { .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].price").value(equalTo(20_000))) .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].name").value(equalTo("토다리"))) .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].price").value(equalTo(200_000))); - } } diff --git a/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java index 901e31b6d..1c3984e7c 100644 --- a/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java @@ -8,33 +8,17 @@ import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import com.fasterxml.jackson.databind.ObjectMapper; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MockMvc; -import server.haengdong.application.BillActionService; import server.haengdong.exception.HaengdongErrorCode; import server.haengdong.exception.HaengdongException; import server.haengdong.presentation.request.BillActionSaveRequest; -import server.haengdong.presentation.request.BillActionsSaveRequest; import server.haengdong.presentation.request.BillActionUpdateRequest; +import server.haengdong.presentation.request.BillActionsSaveRequest; -@WebMvcTest(BillActionController.class) -class BillActionControllerTest { - - @Autowired - private MockMvc mockMvc; - - @Autowired - private ObjectMapper objectMapper; - - @MockBean - private BillActionService billActionService; +class BillActionControllerTest extends ControllerTestSupport { @DisplayName("지출 내역을 생성한다.") @Test diff --git a/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java b/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java new file mode 100644 index 000000000..a9897d9f0 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java @@ -0,0 +1,47 @@ +package server.haengdong.presentation; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.FilterType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import server.haengdong.application.ActionService; +import server.haengdong.application.AuthService; +import server.haengdong.application.BillActionService; +import server.haengdong.application.EventService; +import server.haengdong.application.MemberActionService; + +@WebMvcTest( + controllers = { + EventController.class, + ActionController.class, + BillActionController.class, + MemberActionController.class + }, + excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {WebMvcConfigurer.class})} +) +abstract class ControllerTestSupport { + + @Autowired + protected MockMvc mockMvc; + @Autowired + protected ObjectMapper objectMapper; + + @MockBean + protected EventService eventService; + + @MockBean + protected AuthService authService; + + @MockBean + protected ActionService actionService; + + @MockBean + protected MemberActionService memberActionService; + + @MockBean + protected BillActionService billActionService; +} diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java index 347b734bb..4ba7bc4a9 100644 --- a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java @@ -7,52 +7,42 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import com.fasterxml.jackson.databind.ObjectMapper; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MockMvc; -import server.haengdong.application.EventService; import server.haengdong.application.request.EventAppRequest; import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; import server.haengdong.application.response.MembersAppResponse; +import server.haengdong.presentation.request.EventLoginRequest; import server.haengdong.presentation.request.EventSaveRequest; import server.haengdong.presentation.request.MemberUpdateRequest; -@WebMvcTest(EventController.class) -class EventControllerTest { - @Autowired - private MockMvc mockMvc; - - @Autowired - private ObjectMapper objectMapper; - - @MockBean - private EventService eventService; +class EventControllerTest extends ControllerTestSupport { @DisplayName("이벤트를 생성한다.") @Test void saveEvent() throws Exception { - EventSaveRequest eventSaveRequest = new EventSaveRequest("토다리"); + EventSaveRequest eventSaveRequest = new EventSaveRequest("토다리", "0987"); String requestBody = objectMapper.writeValueAsString(eventSaveRequest); String eventId = "망쵸토큰"; EventAppResponse eventAppResponse = new EventAppResponse(eventId); given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); + given(authService.createToken(eventId)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("eventToken"); mockMvc.perform(post("/api/events") .contentType(MediaType.APPLICATION_JSON) .content(requestBody)) .andDo(print()) .andExpect(status().isOk()) + .andExpect(cookie().value("eventToken", "jwtToken")) .andExpect(jsonPath("$.eventId").value("망쵸토큰")); } @@ -96,4 +86,21 @@ void updateMember() throws Exception { .andDo(print()) .andExpect(status().isOk()); } + + @DisplayName("행사 어드민이 로그인한다.") + @Test + void loginEvent() throws Exception { + String token = "TOKEN"; + EventLoginRequest eventLoginRequest = new EventLoginRequest("1234"); + String requestBody = objectMapper.writeValueAsString(eventLoginRequest); + given(authService.createToken(token)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("eventToken"); + + mockMvc.perform(post("/api/events/{eventId}/login", token) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(status().isOk()); + } } diff --git a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java index a195311d1..1e8fa239f 100644 --- a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java @@ -10,30 +10,14 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import com.fasterxml.jackson.databind.ObjectMapper; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MockMvc; -import server.haengdong.application.MemberActionService; import server.haengdong.application.response.CurrentMemberAppResponse; import server.haengdong.presentation.request.MemberActionsSaveRequest; -@WebMvcTest(MemberActionController.class) -class MemberActionControllerTest { - - @Autowired - private MockMvc mockMvc; - - @Autowired - private ObjectMapper objectMapper; - - @MockBean - private MemberActionService memberActionService; +class MemberActionControllerTest extends ControllerTestSupport { @DisplayName("참여자 행동을 추가한다.") @Test diff --git a/server/src/test/java/server/haengdong/support/fixture/Fixture.java b/server/src/test/java/server/haengdong/support/fixture/Fixture.java new file mode 100644 index 000000000..eb30d8d5c --- /dev/null +++ b/server/src/test/java/server/haengdong/support/fixture/Fixture.java @@ -0,0 +1,9 @@ +package server.haengdong.support.fixture; + +import server.haengdong.domain.event.Event; + +public class Fixture { + + public static final Event EVENT1 = new Event("쿠키", "1234", "TOKEN1"); + public static final Event EVENT2 = new Event("웨디", "1234", "TOKEN2"); +} diff --git a/server/src/test/resources/application.yml b/server/src/test/resources/application.yml deleted file mode 100644 index 2d02b2712..000000000 --- a/server/src/test/resources/application.yml +++ /dev/null @@ -1,18 +0,0 @@ -spring: - h2: - console: - enabled: true - path: /h2-console - datasource: - url: jdbc:h2:mem:database - jpa: - defer-datasource-initialization: true - show-sql: true - properties: - hibernate: - format_sql: true - hibernate: - ddl-auto: create-drop -cors: - max-age: 3600 - allowed-origins: http://localhost:8080 From 7bd9420f6d30b58fc8d1b218b62be887e32864dc Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Wed, 7 Aug 2024 11:32:37 +0900 Subject: [PATCH 120/178] =?UTF-8?q?fix:=20=EC=BF=A0=ED=82=A4=20=EC=9D=B8?= =?UTF-8?q?=EC=A6=9D=20=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95=20(#222)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: khabh <khabh@naver.com> --- .../src/main/java/server/haengdong/config/AdminInterceptor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/server/haengdong/config/AdminInterceptor.java b/server/src/main/java/server/haengdong/config/AdminInterceptor.java index e8b9793ed..da9149b29 100644 --- a/server/src/main/java/server/haengdong/config/AdminInterceptor.java +++ b/server/src/main/java/server/haengdong/config/AdminInterceptor.java @@ -36,7 +36,7 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons private void validateToken(HttpServletRequest request) { String token = authenticationExtractor.extract(request, authService.getTokenName()); String tokenEventId = authService.findEventIdByToken(token); - String eventId = request.getRequestURI().split("/")[2]; + String eventId = request.getRequestURI().split("/")[3]; if (!tokenEventId.equals(eventId)) { throw new AuthenticationException(); } From 79bd41cee92d201bcfac4e03f248a4f5fb29634c Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Wed, 7 Aug 2024 19:37:02 +0900 Subject: [PATCH 121/178] =?UTF-8?q?fix:=20=EC=BF=A0=ED=82=A4=20=EC=9D=B8?= =?UTF-8?q?=EC=A6=9D=20=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95=20(#235)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/server/haengdong/config/AdminInterceptor.java | 5 +++-- server/src/main/resources/application.yml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/server/src/main/java/server/haengdong/config/AdminInterceptor.java b/server/src/main/java/server/haengdong/config/AdminInterceptor.java index da9149b29..c3ca1c943 100644 --- a/server/src/main/java/server/haengdong/config/AdminInterceptor.java +++ b/server/src/main/java/server/haengdong/config/AdminInterceptor.java @@ -3,6 +3,7 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpMethod; import org.springframework.web.servlet.HandlerInterceptor; import server.haengdong.application.AuthService; import server.haengdong.exception.AuthenticationException; @@ -23,8 +24,8 @@ public AdminInterceptor(AuthService authService, AuthenticationExtractor authent public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { log.trace("login request = {}", request.getRequestURI()); - String method = request.getMethod(); - if (method.equals("GET")) { + HttpMethod method = HttpMethod.valueOf(request.getMethod()); + if (HttpMethod.GET.equals(method) || HttpMethod.OPTIONS.equals(method)) { return true; } diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index e3465c9ad..28c87485f 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -29,7 +29,7 @@ security: expire-length: 604800 # 1주일 cookie: - http-only: true + http-only: false secure: false path: / max-age: 7D From 63c93dfde04849a6c855c6bb0bd26af98821351f Mon Sep 17 00:00:00 2001 From: Juhwan Kim <13selfesteem91@naver.com> Date: Thu, 8 Aug 2024 10:50:29 +0900 Subject: [PATCH 122/178] =?UTF-8?q?refactor:=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=9E=AC=EC=A0=95=EC=9D=98=20(#227)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 에러 코드 재정의 Co-authored-by: 3juhwan <13selfesteem91@naver.com> * fix: 변수를 받는 예외 메세지 수정 Co-authored-by: 3juhwan <13selfesteem91@naver.com> --------- Co-authored-by: kunsanglee <gosmdochee2@gmail.com> Co-authored-by: Arachne <66822642+Arachneee@users.noreply.github.com> --- .../haengdong/application/ActionService.java | 2 +- .../haengdong/application/AuthService.java | 3 +- .../application/BillActionService.java | 8 +-- .../haengdong/application/EventService.java | 6 +- .../application/MemberActionFactory.java | 3 +- .../application/MemberActionService.java | 10 +-- .../haengdong/config/AdminInterceptor.java | 3 +- .../haengdong/domain/action/BillAction.java | 14 ++-- .../domain/action/CurrentMembers.java | 4 +- .../haengdong/domain/action/MemberAction.java | 14 ++++ .../domain/action/MemberActionStatus.java | 4 +- .../server/haengdong/domain/event/Event.java | 15 ++-- .../exception/AuthenticationException.java | 15 ++++ .../haengdong/exception/ErrorResponse.java | 8 +-- .../exception/GlobalExceptionHandler.java | 6 +- .../exception/HaengdongErrorCode.java | 70 ++++++++++++++----- .../exception/HaengdongException.java | 10 +-- .../auth/AuthenticationExtractor.java | 5 +- .../request/BillActionSaveRequest.java | 4 +- .../request/BillActionUpdateRequest.java | 10 +-- .../request/BillActionsSaveRequest.java | 5 +- .../request/EventLoginRequest.java | 8 +-- .../request/EventSaveRequest.java | 4 +- .../request/MemberActionsSaveRequest.java | 2 +- .../request/MemberUpdateRequest.java | 4 +- .../application/ActionServiceTest.java | 2 +- .../domain/action/BillActionTest.java | 6 +- .../haengdong/domain/event/EventTest.java | 4 +- .../BillActionControllerTest.java | 2 +- 29 files changed, 156 insertions(+), 95 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/ActionService.java b/server/src/main/java/server/haengdong/application/ActionService.java index bda638756..824b5afb9 100644 --- a/server/src/main/java/server/haengdong/application/ActionService.java +++ b/server/src/main/java/server/haengdong/application/ActionService.java @@ -24,7 +24,7 @@ public class ActionService { public List<MemberBillReportAppResponse> getMemberBillReports(String token) { Event event = eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); List<BillAction> billActions = billActionRepository.findByAction_Event(event); List<MemberAction> memberActions = memberActionRepository.findAllByEvent(event); diff --git a/server/src/main/java/server/haengdong/application/AuthService.java b/server/src/main/java/server/haengdong/application/AuthService.java index 6a22fcbe2..d9352ad53 100644 --- a/server/src/main/java/server/haengdong/application/AuthService.java +++ b/server/src/main/java/server/haengdong/application/AuthService.java @@ -4,6 +4,7 @@ import java.util.Map; import server.haengdong.domain.TokenProvider; import server.haengdong.exception.AuthenticationException; +import server.haengdong.exception.HaengdongErrorCode; public class AuthService { @@ -30,7 +31,7 @@ public String findEventIdByToken(String token) { private void validateToken(String token) { if (!tokenProvider.validateToken(token)) { - throw new AuthenticationException(); + throw new AuthenticationException(HaengdongErrorCode.TOKEN_INVALID); } } diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java index 68abb466e..468508d07 100644 --- a/server/src/main/java/server/haengdong/application/BillActionService.java +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -45,7 +45,7 @@ private Action createStartAction(Event event) { @Transactional public void updateBillAction(String token, Long actionId, BillActionUpdateAppRequest request) { BillAction billAction = billActionRepository.findByAction_Id(actionId) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_BILL_ACTION)); + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); validateToken(token, billAction); @@ -56,19 +56,19 @@ public void updateBillAction(String token, Long actionId, BillActionUpdateAppReq private void validateToken(String token, BillAction billAction) { Event event = billAction.getEvent(); if (event.isTokenMismatch(token)) { - throw new HaengdongException(HaengdongErrorCode.NOT_FOUND_BILL_ACTION); + throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND); } } private Event getEvent(String eventToken) { return eventRepository.findByToken(eventToken) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); } @Transactional public void deleteBillAction(String token, Long actionId) { Event event = eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); billActionRepository.deleteByAction_EventAndActionId(event, actionId); } diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java index 01f198571..3408a6215 100644 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -112,19 +112,19 @@ public void updateMember(String token, String memberName, MemberUpdateAppRequest private void validateMemberNameUnique(Event event, String updatedMemberName) { boolean isMemberNameExist = memberActionRepository.existsByAction_EventAndMemberName(event, updatedMemberName); if (isMemberNameExist) { - throw new HaengdongException(HaengdongErrorCode.DUPLICATED_MEMBER_NAME); + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); } } public void validatePassword(EventLoginAppRequest request) throws HaengdongException { Event event = getEvent(request.token()); if (event.isSamePassword(request.password())) { - throw new AuthenticationException(); + throw new AuthenticationException(HaengdongErrorCode.PASSWORD_INVALID); } } private Event getEvent(String token) { return eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); } } diff --git a/server/src/main/java/server/haengdong/application/MemberActionFactory.java b/server/src/main/java/server/haengdong/application/MemberActionFactory.java index 9d9afb6ac..c0a171642 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionFactory.java +++ b/server/src/main/java/server/haengdong/application/MemberActionFactory.java @@ -1,7 +1,6 @@ package server.haengdong.application; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; @@ -48,7 +47,7 @@ private void validateMemberNames(MemberActionsSaveAppRequest request) { long uniqueCount = memberNames.stream().distinct().count(); if (uniqueCount != memberNames.size()) { - throw new HaengdongException(HaengdongErrorCode.DUPLICATED_MEMBER_ACTION); + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); } } diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java index 749771259..3fef4deb4 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionService.java +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -56,12 +56,12 @@ public List<CurrentMemberAppResponse> getCurrentMembers(String token) { private Event findEvent(String token) { return eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); } public void deleteMember(String token, String memberName) { Event event = eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); memberActionRepository.deleteAllByEventAndMemberName(event, memberName); } @@ -69,11 +69,11 @@ public void deleteMember(String token, String memberName) { @Transactional public void deleteMemberAction(String token, Long actionId) { Event event = eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)); + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); Action action = actionRepository.findByIdAndEvent(actionId, event) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_ACTION)); + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.ACTION_NOT_FOUND)); MemberAction memberAction = memberActionRepository.findByAction(action) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.NOT_FOUND_MEMBER_ACTION)); + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_ACTION_NOT_FOUND)); memberActionRepository.deleteAllByMemberNameAndMinSequence(memberAction.getMemberName(), memberAction.getSequence()); diff --git a/server/src/main/java/server/haengdong/config/AdminInterceptor.java b/server/src/main/java/server/haengdong/config/AdminInterceptor.java index c3ca1c943..af24b783b 100644 --- a/server/src/main/java/server/haengdong/config/AdminInterceptor.java +++ b/server/src/main/java/server/haengdong/config/AdminInterceptor.java @@ -7,6 +7,7 @@ import org.springframework.web.servlet.HandlerInterceptor; import server.haengdong.application.AuthService; import server.haengdong.exception.AuthenticationException; +import server.haengdong.exception.HaengdongErrorCode; import server.haengdong.infrastructure.auth.AuthenticationExtractor; @Slf4j @@ -39,7 +40,7 @@ private void validateToken(HttpServletRequest request) { String tokenEventId = authService.findEventIdByToken(token); String eventId = request.getRequestURI().split("/")[3]; if (!tokenEventId.equals(eventId)) { - throw new AuthenticationException(); + throw new AuthenticationException(HaengdongErrorCode.FORBIDDEN); } } } diff --git a/server/src/main/java/server/haengdong/domain/action/BillAction.java b/server/src/main/java/server/haengdong/domain/action/BillAction.java index 738b04d39..1a50db47d 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillAction.java +++ b/server/src/main/java/server/haengdong/domain/action/BillAction.java @@ -20,10 +20,10 @@ @Entity public class BillAction implements Comparable<BillAction> { - private static final int MIN_TITLE_LENGTH = 2; - private static final int MAX_TITLE_LENGTH = 30; - private static final long MIN_PRICE = 1L; - private static final long MAX_PRICE = 10_000_000L; + public static final int MIN_TITLE_LENGTH = 1; + public static final int MAX_TITLE_LENGTH = 30; + public static final long MIN_PRICE = 1L; + public static final long MAX_PRICE = 10_000_000L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -53,15 +53,13 @@ private BillAction(Long id, Action action, String title, Long price) { private void validateTitle(String title) { int titleLength = title.trim().length(); if (titleLength < MIN_TITLE_LENGTH || titleLength > MAX_TITLE_LENGTH) { - throw new HaengdongException(HaengdongErrorCode.BAD_REQUEST, - String.format("앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다.", MIN_TITLE_LENGTH, MAX_TITLE_LENGTH)); + throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_TITLE_INVALID); } } private void validatePrice(Long price) { if (price < MIN_PRICE || price > MAX_PRICE) { - throw new HaengdongException(HaengdongErrorCode.BAD_REQUEST, - String.format("지출 금액은 %,d 이하의 자연수여야 합니다.", MAX_PRICE)); + throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_PRICE_INVALID); } } diff --git a/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java b/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java index 082b9139d..7706c05d1 100644 --- a/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java +++ b/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java @@ -56,10 +56,10 @@ public CurrentMembers addMemberAction(MemberAction memberAction) { public void validate(String memberName, MemberActionStatus memberActionStatus) { if (memberActionStatus == MemberActionStatus.IN && members.contains(memberName)) { - throw new HaengdongException(HaengdongErrorCode.INVALID_MEMBER_IN_ACTION); + throw new HaengdongException(HaengdongErrorCode.MEMBER_ALREADY_EXIST); } if (memberActionStatus == MemberActionStatus.OUT && !members.contains(memberName)) { - throw new HaengdongException(HaengdongErrorCode.INVALID_MEMBER_OUT_ACTION); + throw new HaengdongException(HaengdongErrorCode.MEMBER_NOT_EXIST); } } diff --git a/server/src/main/java/server/haengdong/domain/action/MemberAction.java b/server/src/main/java/server/haengdong/domain/action/MemberAction.java index 1e78820b2..3faf65bde 100644 --- a/server/src/main/java/server/haengdong/domain/action/MemberAction.java +++ b/server/src/main/java/server/haengdong/domain/action/MemberAction.java @@ -12,12 +12,17 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Entity public class MemberAction implements Comparable<MemberAction> { + public static final int MIN_NAME_LENGTH = 1; + public static final int MAX_NAME_LENGTH = 4; + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @@ -33,13 +38,22 @@ public class MemberAction implements Comparable<MemberAction> { private Long memberGroupId; public MemberAction(Action action, String memberName, MemberActionStatus status, Long memberGroupId) { + validateMemberName(memberName); this.action = action; this.memberName = memberName; this.status = status; this.memberGroupId = memberGroupId; } + private void validateMemberName(String memberName) { + int memberLength = memberName.length(); + if (memberLength < MIN_NAME_LENGTH || memberLength > MAX_NAME_LENGTH) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_LENGTH_INVALID); + } + } + public void updateMemberName(String memberName) { + validateMemberName(memberName); this.memberName = memberName; } diff --git a/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java b/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java index 0a20817fd..76c5a66d4 100644 --- a/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java +++ b/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java @@ -13,7 +13,7 @@ public static MemberActionStatus of(String status) { return Arrays.stream(MemberActionStatus.values()) .filter(s -> s.name().equals(status)) .findFirst() - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BAD_REQUEST, - "존재하지 않는 인원 변동 액션입니다.")); + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_ACTION_STATUS_INVALID, + String.format(HaengdongErrorCode.MEMBER_ACTION_STATUS_INVALID.getMessage(), status))); } } diff --git a/server/src/main/java/server/haengdong/domain/event/Event.java b/server/src/main/java/server/haengdong/domain/event/Event.java index f43145f0d..e90becb3c 100644 --- a/server/src/main/java/server/haengdong/domain/event/Event.java +++ b/server/src/main/java/server/haengdong/domain/event/Event.java @@ -17,10 +17,11 @@ @Entity public class Event { - private static final int MIN_NAME_LENGTH = 2; - private static final int MAX_NAME_LENGTH = 20; + public static final int MIN_NAME_LENGTH = 1; + public static final int MAX_NAME_LENGTH = 20; + public static final int PASSWORD_LENGTH = 4; private static final String SPACES = " "; - private static final Pattern PASSWORD_PATTERN = Pattern.compile("^\\d{4}$"); + private static final Pattern PASSWORD_PATTERN = Pattern.compile(String.format("^\\d{%d}$", PASSWORD_LENGTH)); @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -41,16 +42,16 @@ public Event(String name, String password, String token) { } private void validateName(String name) { - int nameLength = name.length(); + int nameLength = name.trim().length(); if (nameLength < MIN_NAME_LENGTH || MAX_NAME_LENGTH < nameLength) { - throw new HaengdongException(HaengdongErrorCode.BAD_REQUEST, + throw new HaengdongException(HaengdongErrorCode.EVENT_NAME_LENGTH_INVALID, String.format("행사 이름은 %d자 이상 %d자 이하만 입력 가능합니다. 입력한 이름 길이 : %d", MIN_NAME_LENGTH, MAX_NAME_LENGTH, name.length())); } if (isBlankContinuous(name)) { - throw new HaengdongException(HaengdongErrorCode.BAD_REQUEST, + throw new HaengdongException(HaengdongErrorCode.EVENT_NAME_CONSECUTIVE_SPACES, String.format("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s", name)); } } @@ -58,7 +59,7 @@ private void validateName(String name) { private void validatePassword(String password) { Matcher matcher = PASSWORD_PATTERN.matcher(password); if (!matcher.matches()) { - throw new HaengdongException(HaengdongErrorCode.BAD_REQUEST, "비밀번호는 4자리 숫자만 가능합니다."); + throw new HaengdongException(HaengdongErrorCode.EVENT_PASSWORD_FORMAT_INVALID, "비밀번호는 4자리 숫자만 가능합니다."); } } diff --git a/server/src/main/java/server/haengdong/exception/AuthenticationException.java b/server/src/main/java/server/haengdong/exception/AuthenticationException.java index 78a16e295..2efcb16e7 100644 --- a/server/src/main/java/server/haengdong/exception/AuthenticationException.java +++ b/server/src/main/java/server/haengdong/exception/AuthenticationException.java @@ -1,4 +1,19 @@ package server.haengdong.exception; +import lombok.Getter; + +@Getter public class AuthenticationException extends RuntimeException { + + private final HaengdongErrorCode errorCode; + private final String message; + + public AuthenticationException(HaengdongErrorCode errorCode) { + this(errorCode, errorCode.getMessage()); + } + + public AuthenticationException(HaengdongErrorCode errorCode, String message) { + this.errorCode = errorCode; + this.message = message; + } } diff --git a/server/src/main/java/server/haengdong/exception/ErrorResponse.java b/server/src/main/java/server/haengdong/exception/ErrorResponse.java index 69133a66c..d0a2b01a0 100644 --- a/server/src/main/java/server/haengdong/exception/ErrorResponse.java +++ b/server/src/main/java/server/haengdong/exception/ErrorResponse.java @@ -1,15 +1,15 @@ package server.haengdong.exception; public record ErrorResponse( - String code, + HaengdongErrorCode errorCode, String message ) { public static ErrorResponse of(HaengdongErrorCode errorCode) { - return new ErrorResponse(errorCode.getCode(), errorCode.getMessage()); + return new ErrorResponse(errorCode, errorCode.getMessage()); } - public static ErrorResponse of(HaengdongErrorCode errorCode, String message){ - return new ErrorResponse(errorCode.getCode(), message); + public static ErrorResponse of(HaengdongErrorCode errorCode, String message) { + return new ErrorResponse(errorCode, message); } } diff --git a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java index e45f2da67..026ee3452 100644 --- a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java +++ b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java @@ -16,9 +16,9 @@ public class GlobalExceptionHandler { @ExceptionHandler(AuthenticationException.class) - public ResponseEntity<ErrorResponse> authenticationException() { + public ResponseEntity<ErrorResponse> authenticationException(AuthenticationException e) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED) - .body(ErrorResponse.of(HaengdongErrorCode.UNAUTHORIZED)); + .body(ErrorResponse.of(e.getErrorCode())); } @ExceptionHandler({HttpRequestMethodNotSupportedException.class, NoResourceFoundException.class}) @@ -41,7 +41,7 @@ public ResponseEntity<ErrorResponse> handleMethodArgumentNotValidException(Metho .collect(Collectors.joining(", ")); return ResponseEntity.badRequest() - .body(ErrorResponse.of(HaengdongErrorCode.BAD_REQUEST, errorMessage)); + .body(ErrorResponse.of(HaengdongErrorCode.REQUEST_EMPTY, errorMessage)); } @ExceptionHandler(HaengdongException.class) diff --git a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java index 93667d052..bd0866d00 100644 --- a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java +++ b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java @@ -1,29 +1,63 @@ package server.haengdong.exception; import lombok.Getter; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.event.Event; @Getter public enum HaengdongErrorCode { - BAD_REQUEST("R_001", "잘못된 요청입니다."), - NO_RESOURCE_REQUEST("R_002", "잘못된 엔드포인트입니다."), - MESSAGE_NOT_READABLE("R_003", "읽을 수 없는 요청 형식입니다."), - UNAUTHORIZED("A_001", "인증에 실패했습니다."), - INTERNAL_SERVER_ERROR("S_001", "서버 내부에서 에러가 발생했습니다."), - DUPLICATED_MEMBER_NAME("EV_001", "중복된 행사 참여 인원 이름이 존재합니다."), - NOT_FOUND_EVENT("EV_400", "존재하지 않는 행사입니다."), - DUPLICATED_MEMBER_ACTION("MA_001", "중복된 인원이 존재합니다."), - INVALID_MEMBER_IN_ACTION("MA_002", "현재 참여하고 있는 인원이 존재합니다."), - INVALID_MEMBER_OUT_ACTION("MA_003", "현재 참여하고 있지 않는 인원이 존재합니다."), - NOT_FOUND_MEMBER_ACTION("MA_400", "존재하지 않는 멤버 액션입니다."), - NOT_FOUND_BILL_ACTION("BA_400", "존재하지 않는 지출 액션입니다."), - NOT_FOUND_ACTION("AC_400", "존재하지 않는 액션입니다."), - ; - - private final String code; + + /* Domain */ + + EVENT_NOT_FOUND("존재하지 않는 행사입니다."), + EVENT_NAME_LENGTH_INVALID(String.format("행사 이름은 %d자 이상 %d자 이하만 입력 가능합니다.", + Event.MIN_NAME_LENGTH, + Event.MAX_NAME_LENGTH)), + EVENT_NAME_CONSECUTIVE_SPACES("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s"), + EVENT_PASSWORD_FORMAT_INVALID(String.format("비밀번호는 %d자리 숫자만 가능합니다.", Event.PASSWORD_LENGTH)), + + ACTION_NOT_FOUND("존재하지 않는 액션입니다."), + + MEMBER_NAME_LENGTH_INVALID(String.format("멤버 이름은 %d자 이상 %d자 이하만 입력 가능합니다.", + MemberAction.MIN_NAME_LENGTH, + MemberAction.MAX_NAME_LENGTH)), + MEMBER_NAME_DUPLICATE("중복된 행사 참여 인원 이름이 존재합니다."), + MEMBER_NOT_EXIST("현재 참여하고 있지 않는 인원이 존재합니다."), + MEMBER_ALREADY_EXIST("현재 참여하고 있는 인원이 존재합니다."), + + MEMBER_ACTION_NOT_FOUND("존재하지 않는 멤버 액션입니다."), + MEMBER_ACTION_STATUS_INVALID("멤버 액션은 IN, OUT만 가능합니다. 입력한 멤버 액션: %s"), + + BILL_ACTION_NOT_FOUND("존재하지 않는 지출 액션입니다."), + BILL_ACTION_TITLE_INVALID(String.format("앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다.", + BillAction.MIN_TITLE_LENGTH, + BillAction.MAX_TITLE_LENGTH)), + BILL_ACTION_PRICE_INVALID(String.format("지출 금액은 %,d 이하의 자연수여야 합니다.", BillAction.MAX_PRICE)), + + /* Authentication */ + + PASSWORD_INVALID("비밀번호가 일치하지 않습니다."), + + TOKEN_NOT_FOUND("토큰이 존재하지 않습니다."), + TOKEN_EXPIRED("만료된 토큰입니다."), + TOKEN_INVALID("유효하지 않은 토큰입니다."), + + FORBIDDEN("접근할 수 없는 행사입니다."), + + /* Request Validation */ + + REQUEST_EMPTY("입력 값은 공백일 수 없습니다.") + + /* System */, + + MESSAGE_NOT_READABLE("읽을 수 없는 요청입니다."), + NO_RESOURCE_REQUEST("존재하지 않는 자원입니다."), + INTERNAL_SERVER_ERROR("서버 내부에서 에러가 발생했습니다."); + private final String message; - HaengdongErrorCode(String code, String message) { - this.code = code; + HaengdongErrorCode(String message) { this.message = message; } } diff --git a/server/src/main/java/server/haengdong/exception/HaengdongException.java b/server/src/main/java/server/haengdong/exception/HaengdongException.java index d418a2feb..b86fe4ffc 100644 --- a/server/src/main/java/server/haengdong/exception/HaengdongException.java +++ b/server/src/main/java/server/haengdong/exception/HaengdongException.java @@ -9,19 +9,11 @@ public class HaengdongException extends RuntimeException { private final String message; public HaengdongException(HaengdongErrorCode errorCode) { - this(errorCode, null); + this(errorCode, errorCode.getMessage()); } public HaengdongException(HaengdongErrorCode errorCode, String message) { this.errorCode = errorCode; this.message = message; } - - @Override - public String getMessage() { - if (message == null) { - return errorCode.getMessage(); - } - return message; - } } diff --git a/server/src/main/java/server/haengdong/infrastructure/auth/AuthenticationExtractor.java b/server/src/main/java/server/haengdong/infrastructure/auth/AuthenticationExtractor.java index 74489577d..4972de48a 100644 --- a/server/src/main/java/server/haengdong/infrastructure/auth/AuthenticationExtractor.java +++ b/server/src/main/java/server/haengdong/infrastructure/auth/AuthenticationExtractor.java @@ -4,19 +4,20 @@ import jakarta.servlet.http.HttpServletRequest; import java.util.Arrays; import server.haengdong.exception.AuthenticationException; +import server.haengdong.exception.HaengdongErrorCode; public class AuthenticationExtractor { public String extract(HttpServletRequest request, String cookieName) { Cookie[] cookies = request.getCookies(); if (cookies == null) { - throw new AuthenticationException(); + throw new AuthenticationException(HaengdongErrorCode.TOKEN_NOT_FOUND); } return Arrays.stream(cookies) .filter(cookie -> cookieName.equals(cookie.getName())) .findFirst() - .orElseThrow(AuthenticationException::new) + .orElseThrow(() -> new AuthenticationException(HaengdongErrorCode.TOKEN_NOT_FOUND)) .getValue(); } } diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java index a0d878f7f..a47ff8316 100644 --- a/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java @@ -6,10 +6,10 @@ public record BillActionSaveRequest( - @NotBlank + @NotBlank(message = "지출 내역 제목은 공백일 수 없습니다.") String title, - @NotNull + @NotNull(message = "지출 금액은 공백일 수 없습니다.") Long price ) { diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java index 6f1a0a734..680006816 100644 --- a/server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java @@ -6,13 +6,13 @@ public record BillActionUpdateRequest( - @NotBlank + @NotBlank(message = "지출 내역 제목은 공백일 수 없습니다.") String title, - @NotNull + @NotNull(message = "지출 금액은 공백일 수 없습니다.") Long price ) { - public BillActionUpdateAppRequest toAppResponse() { - return new BillActionUpdateAppRequest(title, price); - } + public BillActionUpdateAppRequest toAppResponse() { + return new BillActionUpdateAppRequest(title, price); + } } diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java index 68784039b..42bf86149 100644 --- a/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java @@ -4,7 +4,10 @@ import java.util.List; import server.haengdong.application.request.BillActionAppRequest; -public record BillActionsSaveRequest(@Valid List<BillActionSaveRequest> actions) { +public record BillActionsSaveRequest( + + @Valid List<BillActionSaveRequest> actions +) { public List<BillActionAppRequest> toAppRequests() { return actions.stream() diff --git a/server/src/main/java/server/haengdong/presentation/request/EventLoginRequest.java b/server/src/main/java/server/haengdong/presentation/request/EventLoginRequest.java index d1e743821..a1286e903 100644 --- a/server/src/main/java/server/haengdong/presentation/request/EventLoginRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/EventLoginRequest.java @@ -5,10 +5,10 @@ public record EventLoginRequest( - @NotBlank + @NotBlank(message = "비밀번호는 공백일 수 없습니다.") String password ) { - public EventLoginAppRequest toAppRequest(String token) { - return new EventLoginAppRequest(token, password); - } + public EventLoginAppRequest toAppRequest(String token) { + return new EventLoginAppRequest(token, password); + } } diff --git a/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java index fb9683916..6bd7cd006 100644 --- a/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java @@ -5,10 +5,10 @@ public record EventSaveRequest( - @NotBlank + @NotBlank(message = "행사 이름은 공백일 수 없습니다.") String eventName, - @NotBlank + @NotBlank(message = "비밀번호는 공백일 수 없습니다.") String password ) { diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java index 0b3fcebae..828fc7b4c 100644 --- a/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java @@ -8,7 +8,7 @@ public record MemberActionsSaveRequest( List<String> members, - @NotBlank + @NotBlank(message = "멤버 액션은 공백일 수 없습니다.") String status ) { diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberUpdateRequest.java index 71f0b4ec7..412457750 100644 --- a/server/src/main/java/server/haengdong/presentation/request/MemberUpdateRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/MemberUpdateRequest.java @@ -4,7 +4,9 @@ import server.haengdong.application.request.MemberUpdateAppRequest; public record MemberUpdateRequest( - @NotBlank String name + + @NotBlank(message = "멤버 이름은 공백일 수 없습니다.") + String name ) { public MemberUpdateAppRequest toAppRequest() { diff --git a/server/src/test/java/server/haengdong/application/ActionServiceTest.java b/server/src/test/java/server/haengdong/application/ActionServiceTest.java index ad6c60aa9..05a622d34 100644 --- a/server/src/test/java/server/haengdong/application/ActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/ActionServiceTest.java @@ -72,6 +72,6 @@ void getMemberBillReports() { void getMemberBillReports1() { assertThatThrownBy(() -> actionService.getMemberBillReports("invalid token")) .isInstanceOf(HaengdongException.class) - .hasMessage(HaengdongErrorCode.NOT_FOUND_EVENT.getMessage()); + .hasMessage(HaengdongErrorCode.EVENT_NOT_FOUND.getMessage()); } } diff --git a/server/src/test/java/server/haengdong/domain/action/BillActionTest.java b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java index 851ed14d9..13e4bca68 100644 --- a/server/src/test/java/server/haengdong/domain/action/BillActionTest.java +++ b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java @@ -14,9 +14,9 @@ class BillActionTest { - @DisplayName("지출 내역 제목의 앞뒤 공백을 제거한 길이가 2 ~ 30자가 아니면 지출을 생성할 수 없다.") + @DisplayName("지출 내역 제목의 앞뒤 공백을 제거한 길이가 1 ~ 30자가 아니면 지출을 생성할 수 없다.") @ParameterizedTest - @ValueSource(strings = {" 감 ", "", " ", "1234567890123456789012345678901"}) + @ValueSource(strings = {"", " ", "1234567890123456789012345678901"}) void validateTitle(String title) { Event event = Fixture.EVENT1; Action action = new Action(event, 1L); @@ -24,7 +24,7 @@ void validateTitle(String title) { assertThatThrownBy(() -> new BillAction(action, title, price)) .isInstanceOf(HaengdongException.class) - .hasMessage("앞뒤 공백을 제거한 지출 내역 제목은 2 ~ 30자여야 합니다."); + .hasMessage("앞뒤 공백을 제거한 지출 내역 제목은 1 ~ 30자여야 합니다."); } @DisplayName("금액이 10,000,000 이하의 자연수가 아니면 지출을 생성할 수 없다.") diff --git a/server/src/test/java/server/haengdong/domain/event/EventTest.java b/server/src/test/java/server/haengdong/domain/event/EventTest.java index 0d5b58519..a7dba49d9 100644 --- a/server/src/test/java/server/haengdong/domain/event/EventTest.java +++ b/server/src/test/java/server/haengdong/domain/event/EventTest.java @@ -26,13 +26,13 @@ void createFailTest1(String eventName) { .hasMessage(String.format("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s", eventName)); } - @DisplayName("이름이 2자 미만이거나 20자 초과인 경우 예외가 발생한다.") + @DisplayName("이름이 1자 미만이거나 20자 초과인 경우 예외가 발생한다.") @ParameterizedTest @ValueSource(strings = {"", " ", "123456789012345678901"}) void createFilTest2(String eventName) { assertThatCode(() -> new Event(eventName, "1234", "TEST_TOKEN")) .isInstanceOf(HaengdongException.class) - .hasMessage(String.format("행사 이름은 2자 이상 20자 이하만 입력 가능합니다. 입력한 이름 길이 : %d", eventName.length())); + .hasMessage(String.format("행사 이름은 1자 이상 20자 이하만 입력 가능합니다. 입력한 이름 길이 : %d", eventName.length())); } @DisplayName("비밀번호는 4자리 숫자 입니다.") diff --git a/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java index 1c3984e7c..4420e369c 100644 --- a/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java @@ -87,7 +87,7 @@ void deleteBillAction() throws Exception { @Test void deleteBillAction1() throws Exception { String eventId = "이상해토큰"; - doThrow(new HaengdongException(HaengdongErrorCode.NOT_FOUND_EVENT)) + doThrow(new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)) .when(billActionService).deleteBillAction(any(String.class), any(Long.class)); mockMvc.perform(delete("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1)) From 3e1c52f2bd886e7f14b995fe778f0c1685ddb8a7 Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Thu, 8 Aug 2024 10:54:20 +0900 Subject: [PATCH 123/178] =?UTF-8?q?fix:=20=EC=BF=A0=ED=82=A4=20=EC=A0=80?= =?UTF-8?q?=EC=9E=A5=20=EC=98=A4=EB=A5=98=202=EC=B0=A8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20(#237)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 쿠키 인증 버그 수정 Co-authored-by: khabh <khabh@naver.com> * fix: 쿠키 인증 버그 수정 --------- Co-authored-by: khabh <khabh@naver.com> --- server/src/main/java/server/haengdong/config/WebMvcConfig.java | 1 + .../server/haengdong/infrastructure/auth/CookieProperties.java | 1 + .../main/java/server/haengdong/presentation/EventController.java | 1 + server/src/main/resources/application.yml | 1 + 4 files changed, 4 insertions(+) diff --git a/server/src/main/java/server/haengdong/config/WebMvcConfig.java b/server/src/main/java/server/haengdong/config/WebMvcConfig.java index 3d2d9f60b..d1caa176f 100644 --- a/server/src/main/java/server/haengdong/config/WebMvcConfig.java +++ b/server/src/main/java/server/haengdong/config/WebMvcConfig.java @@ -33,6 +33,7 @@ public void addCorsMappings(CorsRegistry registry) { .allowedOrigins(allowedOrigins) .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS") .allowedHeaders("*") + .allowCredentials(true) .maxAge(maxAge); } diff --git a/server/src/main/java/server/haengdong/infrastructure/auth/CookieProperties.java b/server/src/main/java/server/haengdong/infrastructure/auth/CookieProperties.java index 40d4252fd..18f867601 100644 --- a/server/src/main/java/server/haengdong/infrastructure/auth/CookieProperties.java +++ b/server/src/main/java/server/haengdong/infrastructure/auth/CookieProperties.java @@ -9,6 +9,7 @@ public record CookieProperties( boolean secure, String domain, String path, + String sameSite, Duration maxAge ) { } diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java index 3a6ce5b97..2e16e6b01 100644 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -96,6 +96,7 @@ private ResponseCookie createResponseCookie(String token) { .secure(cookieProperties.secure()) .domain(cookieProperties.domain()) .path(cookieProperties.path()) + .sameSite(cookieProperties.sameSite()) .maxAge(cookieProperties.maxAge()) .build(); } diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index 28c87485f..481cc25dd 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -32,6 +32,7 @@ cookie: http-only: false secure: false path: / + same-site: none max-age: 7D management: From ae82699689df19cc1b78ebafcf035586a61fdc4c Mon Sep 17 00:00:00 2001 From: JUHA <84626225+khabh@users.noreply.github.com> Date: Thu, 8 Aug 2024 11:04:55 +0900 Subject: [PATCH 124/178] =?UTF-8?q?feat:=20REST=20docs=EB=A5=BC=20?= =?UTF-8?q?=ED=86=B5=ED=95=9C=20=EB=AC=B8=EC=84=9C=ED=99=94=20(#238)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: REST Docs 적용 * feat: REST Docs prettyPrint 및 snippets 적용 * feat: REST Docs에 예외 항목 추가 * test: 행사 액션 이력 조회 테스트 추가 * refactor: 중복된 http-request snippet 제거 * refactor: 사용되지 않는 snippet 제거 * refactor: 빌드 시 자동으로 문서 최신화하도록 gradle 설정 추가 * fix: CookieProperties에 sameSite 옵션 추가 --------- Co-authored-by: Arachne <66822642+Arachneee@users.noreply.github.com> --- server/build.gradle | 34 +++ server/src/docs/asciidoc/billAction.adoc | 121 ++++++++ server/src/docs/asciidoc/event.adoc | 165 +++++++++++ server/src/docs/asciidoc/index.adoc | 18 ++ server/src/docs/asciidoc/memberAction.adoc | 100 +++++++ .../src/docs/asciidoc/memberBillReport.adoc | 17 ++ .../docs/ActionControllerDocsTest.java | 70 +++++ .../docs/BillActionControllerDocsTest.java | 128 ++++++++ .../docs/EventControllerDocsTest.java | 280 ++++++++++++++++++ .../docs/MemberActionControllerDocsTest.java | 159 ++++++++++ .../haengdong/docs/RestDocsSupport.java | 28 ++ .../haengdong/support/fixture/Fixture.java | 2 + 12 files changed, 1122 insertions(+) create mode 100644 server/src/docs/asciidoc/billAction.adoc create mode 100644 server/src/docs/asciidoc/event.adoc create mode 100644 server/src/docs/asciidoc/index.adoc create mode 100644 server/src/docs/asciidoc/memberAction.adoc create mode 100644 server/src/docs/asciidoc/memberBillReport.adoc create mode 100644 server/src/test/java/server/haengdong/docs/ActionControllerDocsTest.java create mode 100644 server/src/test/java/server/haengdong/docs/BillActionControllerDocsTest.java create mode 100644 server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java create mode 100644 server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java create mode 100644 server/src/test/java/server/haengdong/docs/RestDocsSupport.java diff --git a/server/build.gradle b/server/build.gradle index 9e59b348f..deb550da4 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -2,6 +2,7 @@ plugins { id 'java' id 'org.springframework.boot' version '3.3.1' id 'io.spring.dependency-management' version '1.1.5' + id 'org.asciidoctor.jvm.convert' version '3.3.2' } group = 'server' @@ -17,6 +18,7 @@ configurations { compileOnly { extendsFrom annotationProcessor } + asciidoctorExt } repositories { @@ -40,8 +42,40 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + + asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor' + testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc' +} + +ext { + snippetsDir = file('build/generated-snippets') } tasks.named('test') { useJUnitPlatform() + outputs.dir snippetsDir +} + +asciidoctor { + inputs.dir snippetsDir + configurations 'asciidoctorExt' + dependsOn test + baseDirFollowsSourceFile() +} + +tasks.register('copyApiDocuments', Copy) { + doFirst { + delete file('src/main/resources/static/docs') + } + dependsOn asciidoctor + from file("build/docs/asciidoc") + into file("src/main/resources/static/docs") +} + +bootJar { + dependsOn copyApiDocuments +} + +build { + dependsOn copyApiDocuments } diff --git a/server/src/docs/asciidoc/billAction.adoc b/server/src/docs/asciidoc/billAction.adoc new file mode 100644 index 000000000..dfd7e26db --- /dev/null +++ b/server/src/docs/asciidoc/billAction.adoc @@ -0,0 +1,121 @@ +== 지출 액션 + +=== 지출 액션 생성 + +operation::createBillActions[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"REQUEST_EMPTY", + "message":"지출 금액은 비어 있으면 안됩니다." + }, + { + "code":"REQUEST_EMPTY", + "message":"지출 내역은 비어 있으면 안됩니다." + }, + { + "code":"BILL_ACTION_TITLE_INVALID", + "message":"앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다." + }, + { + "code":"BILL_ACTION_PRICE_INVALID", + "message":"지출 금액은 10,000,000 이하의 자연수여야 합니다." + }, + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + } +] +---- + +=== 지출 액션 수정 + +operation::updateBillAction[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"REQUEST_EMPTY", + "message":"지출 내역 제목은 공백일 수 없습니다." + }, + { + "code":"REQUEST_EMPTY", + "message":"지출 금액은 공백일 수 없습니다." + }, + { + "code":"BILL_ACTION_TITLE_INVALID", + "message":"앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다." + }, + { + "code":"BILL_ACTION_PRICE_INVALID", + "message":"지출 금액은 %,d 이하의 자연수여야 합니다." + }, + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"BILL_ACTION_NOT_FOUND", + "message":"존재하지 않는 지출 액션입니다." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + } +] +---- + +=== 지출 액션 삭제 + +operation::deleteBillAction[snippets="path-parameters,http-request,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + } +] +---- diff --git a/server/src/docs/asciidoc/event.adoc b/server/src/docs/asciidoc/event.adoc new file mode 100644 index 000000000..013731e52 --- /dev/null +++ b/server/src/docs/asciidoc/event.adoc @@ -0,0 +1,165 @@ +== 행사 + +=== 행사 생성 + +operation::createEvent[snippets="http-request,request-body,request-fields,response-body,response-fields,http-response,response-cookies"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"REQUEST_EMPTY", + "message":"행사 이름은 공백일 수 없습니다." + }, + { + "code":"EVENT_NAME_LENGTH_INVALID", + "message":"행사 이름은 2자 이상 30자 이하만 입력 가능합니다. 입력한 이름 길이 : 21" + }, + { + "code":"EVENT_NAME_MULTIPLE_BLANK", + "message":"행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : 공백 문자" + }, + { + "code":"EVENT_PASSWORD_INVALID", + "message":"비밀번호는 4자리 숫자만 가능합니다." + } +] +---- + +=== 행사 관리자 로그인 + +operation::eventLogin[snippets="path-parameters,http-request,request-body,request-fields,http-response,response-cookies"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"REQUEST_EMPTY", + "message":"비밀번호는 공백일 수 없습니다." + }, + { + "code":"PASSWORD_INVALID", + "message":"비밀번호가 일치하지 않습니다." + } +] +---- + +=== 행사 정보 조회 + +operation::getEvent[snippets="path-parameters,http-request,response-body,response-fields,http-response"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + } +] +---- + +=== 행사 전체 참여자 목록 조회 + +operation::findAllEventMember[snippets="path-parameters,http-request,response-body,response-fields,http-response,response-fields"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + } +] +---- + +=== 행사 전체 액션 이력 조회 + +operation::findActions[snippets="path-parameters,http-request,http-response,response-fields"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + } +] +---- + +=== 행사 참여자 이름 변경 + +operation::updateEventMemberName[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"REQUEST_EMPTY", + "message":"멤버 이름은 공백일 수 없습니다." + }, + { + "code":"MEMBER_NAME_LENGTH_INVALID", + "message":"멤버 이름은 1자 이상 4자 이하만 입력 가능합니다." + }, + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"MEMBER_NAME_DUPLICATE", + "message":"중복된 행사 참여 인원 이름이 존재합니다." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + } +] +---- + +=== 행사 참여자 삭제 (특정 참여자의 모든 참여자 액션 삭제) + +operation::deleteAllMemberActionByName[snippets="path-parameters,http-request,http-response,request-cookies"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + } +] +---- diff --git a/server/src/docs/asciidoc/index.adoc b/server/src/docs/asciidoc/index.adoc new file mode 100644 index 000000000..3039f2bbf --- /dev/null +++ b/server/src/docs/asciidoc/index.adoc @@ -0,0 +1,18 @@ +:source-highlighter: highlightjs +:hardbreaks: +:toc: left +:doctype: book +:icons: font +:toc-title: 전체 API 목록 +:toclevels: 2 +:sectlinks: +:sectnums: +:sectnumlevels: 2 + += 행동대장 + +include::{docdir}/event.adoc[] +include::{docdir}/memberBillReport.adoc[] +include::{docdir}/memberAction.adoc[] +include::{docdir}/billAction.adoc[] + diff --git a/server/src/docs/asciidoc/memberAction.adoc b/server/src/docs/asciidoc/memberAction.adoc new file mode 100644 index 000000000..897102c8d --- /dev/null +++ b/server/src/docs/asciidoc/memberAction.adoc @@ -0,0 +1,100 @@ +== 참여자 액션 + +=== 참여자 액션 생성 + +operation::createMemberAction[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"REQUEST_EMPTY", + "message":"멤버 액션은 공백일 수 없습니다." + }, + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"MEMBER_ACTION_STATUS_INVALID", + "message":"멤버 액션은 IN, OUT만 가능합니다. 입력한 멤버 액션: I_N" + }, + { + "code":"MEMBER_ALREADY_EXIST", + "message":"현재 참여하고 있는 인원이 존재합니다." + }, + { + "code":"MEMBER_NOT_EXIST", + "message":"현재 참여하고 있지 않는 인원이 존재합니다." + }, + { + "code":"MEMBER_NAME_DUPLICATE", + "message":"중복된 이름이 존재합니다. 입력된 이름: 이상, 이상, 감자, 백호" + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + } +] +---- + +=== 현재 행사에 참여 중인 (탈주 가능한) 참여자 목록 조회 + +operation::getCurrentMembers[snippets="path-parameters,http-request,http-response,response-fields"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + } +] +---- + +=== 참여자 액션 삭제 + +operation::deleteMemberAction[snippets="path-parameters,http-request,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"ACTION_NOT_FOUND", + "message":"존재하지 않는 액션입니다." + }, + { + "code":"MEMBER_ACTION_NOT_FOUND", + "message":"존재하지 않는 멤버 액션입니다." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + } +] +---- diff --git a/server/src/docs/asciidoc/memberBillReport.adoc b/server/src/docs/asciidoc/memberBillReport.adoc new file mode 100644 index 000000000..18bd7d3ef --- /dev/null +++ b/server/src/docs/asciidoc/memberBillReport.adoc @@ -0,0 +1,17 @@ +== 정산 + +=== 참여자별 정산 결과 조회 + +operation::getMemberBillReports[snippets="path-parameters,http-request,response-body,response-fields,http-response,http-request"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + } +] +---- diff --git a/server/src/test/java/server/haengdong/docs/ActionControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/ActionControllerDocsTest.java new file mode 100644 index 000000000..39c2d0bb8 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/ActionControllerDocsTest.java @@ -0,0 +1,70 @@ +package server.haengdong.docs; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import server.haengdong.application.ActionService; +import server.haengdong.application.response.MemberBillReportAppResponse; +import server.haengdong.presentation.ActionController; + +class ActionControllerDocsTest extends RestDocsSupport { + + private final ActionService actionService = mock(ActionService.class); + + @Override + protected Object initController() { + return new ActionController(actionService); + } + + @DisplayName("참여자별 정산 현황을 조회한다.") + @Test + void getMemberBillReports() throws Exception { + List<MemberBillReportAppResponse> memberBillReportAppResponses = List.of( + new MemberBillReportAppResponse("소하", 20_000L), new MemberBillReportAppResponse("토다리", 200_000L)); + + given(actionService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/actions/reports", "망쵸토큰") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].name").value(equalTo("소하"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].price").value(equalTo(20_000))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].name").value(equalTo("토다리"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].price").value(equalTo(200_000))) + .andDo( + document("getMemberBillReports", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("reports").type(JsonFieldType.ARRAY).description("전체 정산 현황 목록"), + fieldWithPath("reports[0].name").type(JsonFieldType.STRING) + .description("참여자 이름"), + fieldWithPath("reports[0].price").type(JsonFieldType.NUMBER) + .description("참여자 정산 금액") + )) + ); + } +} diff --git a/server/src/test/java/server/haengdong/docs/BillActionControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/BillActionControllerDocsTest.java new file mode 100644 index 000000000..7ed6fe6c4 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/BillActionControllerDocsTest.java @@ -0,0 +1,128 @@ +package server.haengdong.docs; + +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; +import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import server.haengdong.application.BillActionService; +import server.haengdong.presentation.BillActionController; +import server.haengdong.presentation.request.BillActionSaveRequest; +import server.haengdong.presentation.request.BillActionUpdateRequest; +import server.haengdong.presentation.request.BillActionsSaveRequest; + +class BillActionControllerDocsTest extends RestDocsSupport { + + private final BillActionService billActionService = mock(BillActionService.class); + + @Override + protected Object initController() { + return new BillActionController(billActionService); + } + + @DisplayName("지출 내역을 생성한다.") + @Test + void saveAllBillAction() throws Exception { + BillActionsSaveRequest request = new BillActionsSaveRequest( + List.of( + new BillActionSaveRequest("뽕족", 10_000L), + new BillActionSaveRequest("인생맥주", 10_000L) + ) + ); + String requestBody = objectMapper.writeValueAsString(request); + String eventId = "쿠키토큰"; + + mockMvc.perform(post("/api/events/{eventId}/bill-actions", eventId) + .contentType(MediaType.APPLICATION_JSON) + .cookie(EVENT_COOKIE) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo(document("createBillActions", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), + requestFields( + fieldWithPath("actions").description("생성할 지출 액션 목록"), + fieldWithPath("actions[0].title").description("생성할 지출 액션의 제목"), + fieldWithPath("actions[0].price").description("생성할 지출 액션의 금액") + ) + )); + } + + @DisplayName("지출 액션을 수정한다.") + @Test + void updateBillAction() throws Exception { + BillActionUpdateRequest request = new BillActionUpdateRequest("뽕족", 10_000L); + + String requestBody = objectMapper.writeValueAsString(request); + String eventId = "웨디토큰"; + + mockMvc.perform(put("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1L) + .cookie(EVENT_COOKIE) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo(document("updateBillAction", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("actionId").description("지출 액션 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), + requestFields( + fieldWithPath("title").description("수정할 지출 액션의 제목"), + fieldWithPath("price").description("수정할 지출 액션의 금액") + ) + )); + } + + @DisplayName("지출 내역을 삭제한다.") + @Test + void deleteBillAction() throws Exception { + String eventId = "토다리토큰"; + + mockMvc.perform(delete("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1) + .cookie(EVENT_COOKIE) + ) + .andDo(print()) + .andExpect(status().isOk()) + .andDo(document("deleteBillAction", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("actionId").description("지출 액션 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ) + )); + } +} diff --git a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java new file mode 100644 index 000000000..68c200398 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java @@ -0,0 +1,280 @@ +package server.haengdong.docs; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; +import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; +import static org.springframework.restdocs.cookies.CookieDocumentation.responseCookies; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; + +import java.time.Duration; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.restdocs.payload.JsonFieldType; +import server.haengdong.application.AuthService; +import server.haengdong.application.EventService; +import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.ActionAppResponse.ActionType; +import server.haengdong.application.response.EventAppResponse; +import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.application.response.MembersAppResponse; +import server.haengdong.infrastructure.auth.CookieProperties; +import server.haengdong.presentation.EventController; +import server.haengdong.presentation.request.EventLoginRequest; +import server.haengdong.presentation.request.EventSaveRequest; +import server.haengdong.presentation.request.MemberUpdateRequest; + +public class EventControllerDocsTest extends RestDocsSupport { + + private final EventService eventService = mock(EventService.class); + private final AuthService authService = mock(AuthService.class); + private final CookieProperties cookieProperties = new CookieProperties( + true, true, "domain", "path", "none", Duration.ofDays(7) + ); + + @Override + protected Object initController() { + return new EventController(eventService, authService, cookieProperties); + } + + @DisplayName("이벤트를 생성한다.") + @Test + void saveEvent() throws Exception { + EventSaveRequest eventSaveRequest = new EventSaveRequest("토다리", "0987"); + String requestBody = objectMapper.writeValueAsString(eventSaveRequest); + String eventId = "쿠키 토큰"; + EventAppResponse eventAppResponse = new EventAppResponse(eventId); + given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); + given(authService.createToken(eventId)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("eventToken"); + + mockMvc.perform(post("/api/events") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(jsonPath("$.eventId").value("쿠키 토큰")) + .andDo( + document("createEvent", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + requestFields( + fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름"), + fieldWithPath("password").type(JsonFieldType.STRING).description("행사 비밀 번호") + ), + responseFields( + fieldWithPath("eventId").type(JsonFieldType.STRING) + .description("행사 ID") + ), + responseCookies( + cookieWithName("eventToken").description("행사 관리자용 토큰") + ) + ) + ); + } + + @DisplayName("토큰으로 행사를 조회한다.") + @Test + void findEventTest() throws Exception { + String eventId = "망쵸토큰"; + EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식"); + given(eventService.findEvent(eventId)).willReturn(eventDetailAppResponse); + + mockMvc.perform(get("/api/events/{eventId}", eventId)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.eventName").value("행동대장 회식")) + .andDo( + document("getEvent", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름") + ) + ) + ); + } + + @DisplayName("행사에 참여한 전체 인원을 중복 없이 조회한다.") + @Test + void findAllMembersTest() throws Exception { + MembersAppResponse memberAppResponse = new MembersAppResponse(List.of("토다리", "쿠키")); + given(eventService.findAllMembers(anyString())).willReturn(memberAppResponse); + + mockMvc.perform(get("/api/events/{eventId}/members", "TOKEN")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.memberNames").isArray()) + .andExpect(jsonPath("$.memberNames[0]").value("토다리")) + .andExpect(jsonPath("$.memberNames[1]").value("쿠키")) + .andDo( + document("findAllEventMember", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("memberNames").type(JsonFieldType.ARRAY) + .description("행사 참여자 목록") + ) + ) + ); + } + + @DisplayName("행사 참여 인원의 이름을 수정한다.") + @Test + void updateMember() throws Exception { + String token = "TOKEN"; + MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest("변경된 이름"); + String requestBody = objectMapper.writeValueAsString(memberUpdateRequest); + + mockMvc.perform(put("/api/events/{eventId}/members/{memberName}", token, "변경 전 이름") + .cookie(EVENT_COOKIE) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("updateEventMemberName", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("memberName").description("참여자 이름") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), + requestFields( + fieldWithPath("name").type(JsonFieldType.STRING).description("수정할 참여자 이름") + ) + ) + ); + } + + @DisplayName("행사 어드민이 로그인한다.") + @Test + void loginEvent() throws Exception { + String token = "TOKEN"; + EventLoginRequest eventLoginRequest = new EventLoginRequest("1234"); + String requestBody = objectMapper.writeValueAsString(eventLoginRequest); + given(authService.createToken(token)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("eventToken"); + + mockMvc.perform(post("/api/events/{eventId}/login", token) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(status().isOk()) + .andDo( + document("eventLogin", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestFields( + fieldWithPath("password").type(JsonFieldType.STRING) + .description("행사 비밀 번호") + ), + responseCookies( + cookieWithName("eventToken").description("행사 관리자용 토큰") + ) + ) + ); + } + + @DisplayName("행사 전체 액션 이력 조회") + @Test + void findActions() throws Exception { + String token = "TOKEN"; + List<ActionAppResponse> actionAppResponses = List.of( + new ActionAppResponse(1L, "망쵸", null, 1L, ActionType.IN), + new ActionAppResponse(2L, "족발", 100L, 2L, ActionType.BILL), + new ActionAppResponse(3L, "인생네컷", 1000L, 3L, ActionType.BILL), + new ActionAppResponse(4L, "망쵸", null, 4L, ActionType.OUT) + ); + given(eventService.findActions(token)).willReturn(actionAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/actions", token) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.steps[0].type").value(equalTo("IN"))) + .andExpect(jsonPath("$.steps[0].members[0]").value(equalTo("망쵸"))) + .andExpect(jsonPath("$.steps[0].actions[0].actionId").value(equalTo(1))) + .andExpect(jsonPath("$.steps[0].actions[0].name").value(equalTo("망쵸"))) + .andExpect(jsonPath("$.steps[0].actions[0].price").value(equalTo(null))) + .andExpect(jsonPath("$.steps[0].actions[0].sequence").value(equalTo(1))) + + .andExpect(jsonPath("$.steps[1].type").value(equalTo("BILL"))) + .andExpect(jsonPath("$.steps[1].members[0]").value(equalTo("망쵸"))) + .andExpect(jsonPath("$.steps[1].actions[0].actionId").value(equalTo(2))) + .andExpect(jsonPath("$.steps[1].actions[0].name").value(equalTo("족발"))) + .andExpect(jsonPath("$.steps[1].actions[0].price").value(equalTo(100))) + .andExpect(jsonPath("$.steps[1].actions[0].sequence").value(equalTo(2))) + + .andExpect(jsonPath("$.steps[1].actions[1].actionId").value(equalTo(3))) + .andExpect(jsonPath("$.steps[1].actions[1].name").value(equalTo("인생네컷"))) + .andExpect(jsonPath("$.steps[1].actions[1].price").value(equalTo(1000))) + .andExpect(jsonPath("$.steps[1].actions[1].sequence").value(equalTo(3))) + + .andExpect(jsonPath("$.steps[2].type").value(equalTo("OUT"))) + .andExpect(jsonPath("$.steps[2].actions[0].actionId").value(equalTo(4))) + .andExpect(jsonPath("$.steps[2].actions[0].name").value(equalTo("망쵸"))) + .andExpect(jsonPath("$.steps[2].actions[0].price").value(equalTo(null))) + .andExpect(jsonPath("$.steps[2].actions[0].sequence").value(equalTo(4))) + + .andDo( + document("findActions", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("steps[].type").type(JsonFieldType.STRING) + .description("액션 유형 [BILL, IN, OUT]"), + fieldWithPath("steps[].members").type(JsonFieldType.ARRAY) + .description("해당 step에 참여한 참여자 목록"), + fieldWithPath("steps[].actions[].actionId").type(JsonFieldType.NUMBER) + .description("액션 ID"), + fieldWithPath("steps[].actions[].name").type(JsonFieldType.STRING) + .description("참여자 액션일 경우 참여자 이름, 지출 액션일 경우 지출 내역 이름"), + fieldWithPath("steps[].actions[].price").type(JsonFieldType.NUMBER).optional() + .description("참여자 액션일 경우 null, 지출 액션일 경우 지출 금액"), + fieldWithPath("steps[].actions[].sequence").type(JsonFieldType.NUMBER) + .description("액션 순서") + ) + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java new file mode 100644 index 000000000..3105eb2c4 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java @@ -0,0 +1,159 @@ +package server.haengdong.docs; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; +import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.restdocs.payload.JsonFieldType; +import server.haengdong.application.MemberActionService; +import server.haengdong.application.response.CurrentMemberAppResponse; +import server.haengdong.presentation.MemberActionController; +import server.haengdong.presentation.request.MemberActionsSaveRequest; + +public class MemberActionControllerDocsTest extends RestDocsSupport { + + private final MemberActionService memberActionService = mock(MemberActionService.class); + + @Override + protected Object initController() { + return new MemberActionController(memberActionService); + } + + @DisplayName("참여자 행동을 추가한다.") + @Test + void saveMemberActionTest() throws Exception { + MemberActionsSaveRequest memberActionsSaveRequest = new MemberActionsSaveRequest( + List.of("웨디", "소하", "토다리", "쿠키"), "IN"); + + String requestBody = objectMapper.writeValueAsString(memberActionsSaveRequest); + + mockMvc.perform(post("/api/events/{eventId}/member-actions", "망쵸토큰") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("createMemberAction", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("토큰 토큰") + ), + requestFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("액션 대상 참여자 목록"), + fieldWithPath("status").type(JsonFieldType.STRING) + .description("참여자 액션 상태 [IN(늦참), OUT(탈주)]") + ) + ) + ); + } + + @DisplayName("현재 참여 인원을 조회합니다.") + @Test + void getCurrentMembers() throws Exception { + List<CurrentMemberAppResponse> currentMemberAppResponses = List.of( + new CurrentMemberAppResponse("소하"), new CurrentMemberAppResponse("토다리")); + + given(memberActionService.getCurrentMembers(any())).willReturn(currentMemberAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/members/current", "망쵸토큰") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members[0].name").value(equalTo("소하"))) + .andExpect(jsonPath("$.members[1].name").value(equalTo("토다리"))) + .andDo( + document("getCurrentMembers", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("액션 대상 참여자 목록"), + fieldWithPath("members[0].name").type(JsonFieldType.STRING) + .description("참여자 이름") + ) + ) + ); + } + + @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") + @Test + void deleteMemberAction() throws Exception { + String eventId = "망쵸토큰"; + Long actionId = 2L; + + mockMvc.perform(delete("/api/events/{eventId}/member-actions/{actionId}", eventId, actionId) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("deleteMemberAction", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("actionId").description("액션 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자용 토큰") + ) + ) + ); + } + + @DisplayName("행사의 전체 참여자 중에서 특정 참여자의 맴버 액션을 전부 삭제한다.") + @Test + void deleteMember() throws Exception { + String eventId = "망쵸토큰"; + String memberName = "행동대장"; + + mockMvc.perform(delete("/api/events/{eventId}/members/{memberName}", eventId, memberName) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("deleteAllMemberActionByName", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("memberName").description("행사 참여자 이름") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자용 토큰") + ) + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/docs/RestDocsSupport.java b/server/src/test/java/server/haengdong/docs/RestDocsSupport.java new file mode 100644 index 000000000..3e6901ba8 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/RestDocsSupport.java @@ -0,0 +1,28 @@ +package server.haengdong.docs; + +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.restdocs.RestDocumentationContextProvider; +import org.springframework.restdocs.RestDocumentationExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +@ExtendWith({RestDocumentationExtension.class}) +abstract class RestDocsSupport { + + protected MockMvc mockMvc; + + protected ObjectMapper objectMapper = new ObjectMapper(); + + @BeforeEach + void setUp(RestDocumentationContextProvider restDocumentation) { + this.mockMvc = MockMvcBuilders.standaloneSetup(initController()) + .apply(documentationConfiguration(restDocumentation)) + .build(); + } + + protected abstract Object initController(); +} diff --git a/server/src/test/java/server/haengdong/support/fixture/Fixture.java b/server/src/test/java/server/haengdong/support/fixture/Fixture.java index eb30d8d5c..fea2bd69a 100644 --- a/server/src/test/java/server/haengdong/support/fixture/Fixture.java +++ b/server/src/test/java/server/haengdong/support/fixture/Fixture.java @@ -1,9 +1,11 @@ package server.haengdong.support.fixture; +import jakarta.servlet.http.Cookie; import server.haengdong.domain.event.Event; public class Fixture { public static final Event EVENT1 = new Event("쿠키", "1234", "TOKEN1"); public static final Event EVENT2 = new Event("웨디", "1234", "TOKEN2"); + public static final Cookie EVENT_COOKIE = new Cookie("eventToken", "토큰토큰"); } From fae2b74f3b95497a8f4a3c34515850304ea31fff Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Thu, 8 Aug 2024 14:25:55 +0900 Subject: [PATCH 125/178] =?UTF-8?q?fix:=20JWT=20=EC=9C=A0=ED=9A=A8?= =?UTF-8?q?=EA=B8=B0=EA=B0=84=20=EB=A7=8C=EB=A3=8C=20=EB=B2=84=EA=B7=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#248)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: JWT 기간 오류 수정 * fix: JWT 기간 오류 수정 --- server/src/main/resources/application.yml | 2 +- server/src/main/resources/config | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index 481cc25dd..bd8fd28af 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -26,7 +26,7 @@ security: jwt: token: secret-key: skdmeejEKJdkDjklDlkj123DKLJ3kDkeDkDKQMEOD1D90D8dE - expire-length: 604800 # 1주일 + expire-length: 604800000 # 1주일 cookie: http-only: false diff --git a/server/src/main/resources/config b/server/src/main/resources/config index 9129bc475..13959710c 160000 --- a/server/src/main/resources/config +++ b/server/src/main/resources/config @@ -1 +1 @@ -Subproject commit 9129bc4756c577a511f7372d6ee7dca6b1925b23 +Subproject commit 13959710cc6d19309aafbc87681d25b9060d935d From 940b2dbecd211a5e3b63437dc1e4c88e1a80bc5f Mon Sep 17 00:00:00 2001 From: Juhwan Kim <13selfesteem91@naver.com> Date: Thu, 8 Aug 2024 17:38:42 +0900 Subject: [PATCH 126/178] =?UTF-8?q?feat:=20=EA=B4=80=EB=A6=AC=EC=9E=90=20?= =?UTF-8?q?=EA=B6=8C=ED=95=9C=20=ED=99=95=EC=9D=B8=20API=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(#259)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 관리자 권한 확인 API 구현 * backend-pull-request workflow 파일 수정 * feat: HTTP Method를 POST에서 GET으로 변경 --- .github/workflows/backend-pull-request.yml | 2 +- server/src/docs/asciidoc/event.adoc | 31 +++ .../presentation/EventController.java | 5 + .../docs/EventControllerDocsTest.java | 185 ++++++++++-------- 4 files changed, 141 insertions(+), 82 deletions(-) diff --git a/.github/workflows/backend-pull-request.yml b/.github/workflows/backend-pull-request.yml index 7e0c561f1..2d7becbfc 100644 --- a/.github/workflows/backend-pull-request.yml +++ b/.github/workflows/backend-pull-request.yml @@ -8,7 +8,7 @@ on: jobs: build: - runs-on: [ self-hosted, backend-dev ] + runs-on: [ ubuntu-latest ] defaults: run: diff --git a/server/src/docs/asciidoc/event.adoc b/server/src/docs/asciidoc/event.adoc index 013731e52..253120e52 100644 --- a/server/src/docs/asciidoc/event.adoc +++ b/server/src/docs/asciidoc/event.adoc @@ -163,3 +163,34 @@ operation::deleteAllMemberActionByName[snippets="path-parameters,http-request,ht } ] ---- + +=== 행사 어드민 권한 확인 + +operation::authenticateEvent[snippets="http-request,http-response,request-cookies"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code": "EVENT_NOT_FOUND", + "message": "존재하지 않는 행사입니다." + }, + { + "code": "TOKEN_NOT_FOUND", + "message": "토큰이 존재하지 않습니다." + }, + { + "code": "TOKEN_EXPIRED", + "message": "만료된 토큰입니다." + }, + { + "code": "TOKEN_INVALID", + "message": "유효하지 않은 토큰입니다." + }, + { + "code": "FORBIDDEN", + "message": "접근할 수 없는 행사입니다." + } +] +---- diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java index 2e16e6b01..6c143b181 100644 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -90,6 +90,11 @@ public ResponseEntity<Void> loginEvent( .build(); } + @GetMapping("/api/events/{eventId}/auth") + public ResponseEntity<Void> authenticate(@PathVariable("eventId") String token) { + return ResponseEntity.ok().build(); + } + private ResponseCookie createResponseCookie(String token) { return ResponseCookie.from(authService.getTokenName(), token) .httpOnly(cookieProperties.httpOnly()) diff --git a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java index 68c200398..67095aae9 100644 --- a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java @@ -71,27 +71,27 @@ void saveEvent() throws Exception { given(authService.getTokenName()).willReturn("eventToken"); mockMvc.perform(post("/api/events") - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) .andDo(print()) .andExpect(status().isOk()) .andExpect(cookie().value("eventToken", "jwtToken")) .andExpect(jsonPath("$.eventId").value("쿠키 토큰")) .andDo( document("createEvent", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - requestFields( - fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름"), - fieldWithPath("password").type(JsonFieldType.STRING).description("행사 비밀 번호") - ), - responseFields( - fieldWithPath("eventId").type(JsonFieldType.STRING) - .description("행사 ID") - ), - responseCookies( - cookieWithName("eventToken").description("행사 관리자용 토큰") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + requestFields( + fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름"), + fieldWithPath("password").type(JsonFieldType.STRING).description("행사 비밀 번호") + ), + responseFields( + fieldWithPath("eventId").type(JsonFieldType.STRING) + .description("행사 ID") + ), + responseCookies( + cookieWithName("eventToken").description("행사 관리자용 토큰") + ) ) ); } @@ -109,14 +109,14 @@ void findEventTest() throws Exception { .andExpect(jsonPath("$.eventName").value("행동대장 회식")) .andDo( document("getEvent", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - responseFields( - fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름") + ) ) ); } @@ -135,15 +135,15 @@ void findAllMembersTest() throws Exception { .andExpect(jsonPath("$.memberNames[1]").value("쿠키")) .andDo( document("findAllEventMember", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - responseFields( - fieldWithPath("memberNames").type(JsonFieldType.ARRAY) - .description("행사 참여자 목록") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("memberNames").type(JsonFieldType.ARRAY) + .description("행사 참여자 목록") + ) ) ); } @@ -156,25 +156,25 @@ void updateMember() throws Exception { String requestBody = objectMapper.writeValueAsString(memberUpdateRequest); mockMvc.perform(put("/api/events/{eventId}/members/{memberName}", token, "변경 전 이름") - .cookie(EVENT_COOKIE) - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + .cookie(EVENT_COOKIE) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) .andDo(print()) .andExpect(status().isOk()) .andDo( document("updateEventMemberName", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID"), - parameterWithName("memberName").description("참여자 이름") - ), - requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") - ), - requestFields( - fieldWithPath("name").type(JsonFieldType.STRING).description("수정할 참여자 이름") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("memberName").description("참여자 이름") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), + requestFields( + fieldWithPath("name").type(JsonFieldType.STRING).description("수정할 참여자 이름") + ) ) ); } @@ -189,25 +189,25 @@ void loginEvent() throws Exception { given(authService.getTokenName()).willReturn("eventToken"); mockMvc.perform(post("/api/events/{eventId}/login", token) - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) .andDo(print()) .andExpect(cookie().value("eventToken", "jwtToken")) .andExpect(status().isOk()) .andDo( document("eventLogin", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - requestFields( - fieldWithPath("password").type(JsonFieldType.STRING) - .description("행사 비밀 번호") - ), - responseCookies( - cookieWithName("eventToken").description("행사 관리자용 토큰") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestFields( + fieldWithPath("password").type(JsonFieldType.STRING) + .description("행사 비밀 번호") + ), + responseCookies( + cookieWithName("eventToken").description("행사 관리자용 토큰") + ) ) ); } @@ -225,7 +225,7 @@ void findActions() throws Exception { given(eventService.findActions(token)).willReturn(actionAppResponses); mockMvc.perform(get("/api/events/{eventId}/actions", token) - .accept(MediaType.APPLICATION_JSON)) + .accept(MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) .andExpect(jsonPath("$.steps[0].type").value(equalTo("IN"))) @@ -255,25 +255,48 @@ void findActions() throws Exception { .andDo( document("findActions", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - responseFields( - fieldWithPath("steps[].type").type(JsonFieldType.STRING) - .description("액션 유형 [BILL, IN, OUT]"), - fieldWithPath("steps[].members").type(JsonFieldType.ARRAY) - .description("해당 step에 참여한 참여자 목록"), - fieldWithPath("steps[].actions[].actionId").type(JsonFieldType.NUMBER) - .description("액션 ID"), - fieldWithPath("steps[].actions[].name").type(JsonFieldType.STRING) - .description("참여자 액션일 경우 참여자 이름, 지출 액션일 경우 지출 내역 이름"), - fieldWithPath("steps[].actions[].price").type(JsonFieldType.NUMBER).optional() - .description("참여자 액션일 경우 null, 지출 액션일 경우 지출 금액"), - fieldWithPath("steps[].actions[].sequence").type(JsonFieldType.NUMBER) - .description("액션 순서") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("steps[].type").type(JsonFieldType.STRING) + .description("액션 유형 [BILL, IN, OUT]"), + fieldWithPath("steps[].members").type(JsonFieldType.ARRAY) + .description("해당 step에 참여한 참여자 목록"), + fieldWithPath("steps[].actions[].actionId").type(JsonFieldType.NUMBER) + .description("액션 ID"), + fieldWithPath("steps[].actions[].name").type(JsonFieldType.STRING) + .description("참여자 액션일 경우 참여자 이름, 지출 액션일 경우 지출 내역 이름"), + fieldWithPath("steps[].actions[].price").type(JsonFieldType.NUMBER).optional() + .description("참여자 액션일 경우 null, 지출 액션일 경우 지출 금액"), + fieldWithPath("steps[].actions[].sequence").type(JsonFieldType.NUMBER) + .description("액션 순서") + ) + ) + ); + } + + @DisplayName("행사 어드민 권한을 확인한다.") + @Test + void authenticateTest() throws Exception { + String token = "TOKEN"; + mockMvc.perform(get("/api/events/{eventId}/auth", token) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + + .andDo( + document("authenticateEvent", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰").optional() + ) ) ); } From f84c194739ea8f051a3338d9bb8d4e0620e0ba26 Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Thu, 8 Aug 2024 20:12:04 +0900 Subject: [PATCH 127/178] =?UTF-8?q?fix:=20=EC=B0=B8=EC=97=AC=EC=9E=90=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=EC=97=90=20Transactional=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(#265)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 3juhwan <13selfesteem91@naver.com> --- .../server/haengdong/application/MemberActionService.java | 1 + server/src/main/resources/application.yml | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java index 3fef4deb4..79318fa98 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionService.java +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -59,6 +59,7 @@ private Event findEvent(String token) { .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); } + @Transactional public void deleteMember(String token, String memberName) { Event event = eventRepository.findByToken(token) .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index bd8fd28af..175faf021 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -47,6 +47,13 @@ logging: org.springframework.web: debug server.haengdong: debug +server: + servlet: + encoding: + charset: UTF-8 + enabled: true + force: true + --- spring: From 927d5d88a4cc9bca66bfd381dfe74147b1953871 Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Fri, 9 Aug 2024 09:55:57 +0900 Subject: [PATCH 128/178] =?UTF-8?q?refactor:=20application.yml=20metrics?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80=20(#269)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/main/resources/application.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index 175faf021..425a2c5a0 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -39,7 +39,7 @@ management: endpoints: web: exposure: - include: logfile + include: logfile, metrics logging: level: @@ -47,6 +47,11 @@ logging: org.springframework.web: debug server.haengdong: debug + file: + name: logs/spring-boot-application.log + path: logs + config: classpath:logback-spring.xml + server: servlet: encoding: From 18f132c78bd187757077932ca5673fcdbeac0744 Mon Sep 17 00:00:00 2001 From: Juhwan Kim <13selfesteem91@naver.com> Date: Fri, 9 Aug 2024 10:26:31 +0900 Subject: [PATCH 129/178] =?UTF-8?q?feat:=20CI/CD=20=EC=88=99=EC=A0=9C=20(#?= =?UTF-8?q?290)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/server/haengdong/HaengdongApplication.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server/src/main/java/server/haengdong/HaengdongApplication.java b/server/src/main/java/server/haengdong/HaengdongApplication.java index 31b6e46e7..0072a5a11 100644 --- a/server/src/main/java/server/haengdong/HaengdongApplication.java +++ b/server/src/main/java/server/haengdong/HaengdongApplication.java @@ -1,12 +1,15 @@ package server.haengdong; +import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +@Slf4j @SpringBootApplication public class HaengdongApplication { public static void main(String[] args) { + log.error("################### 안녕하세요. CI/CD 테스트입니다. ###################"); SpringApplication.run(HaengdongApplication.class, args); } From 97fc7fb6c0d783d6900e6566927aa7177f9b6dfc Mon Sep 17 00:00:00 2001 From: Juhwan Kim <13selfesteem91@naver.com> Date: Fri, 9 Aug 2024 10:38:06 +0900 Subject: [PATCH 130/178] =?UTF-8?q?feat:=20CI/CD=20=EC=88=99=EC=A0=9C=20(#?= =?UTF-8?q?291)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/server/haengdong/presentation/EventController.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java index 6c143b181..356d5216d 100644 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -2,6 +2,7 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseCookie; @@ -23,6 +24,7 @@ import server.haengdong.presentation.response.MembersResponse; import server.haengdong.presentation.response.StepsResponse; +@Slf4j @RequiredArgsConstructor @EnableConfigurationProperties(CookieProperties.class) @RestController @@ -34,6 +36,8 @@ public class EventController { @PostMapping("/api/events") public ResponseEntity<EventResponse> saveEvent(@Valid @RequestBody EventSaveRequest request) { + log.error("################### 안녕하세요. CI/CD 테스트입니다. ###################"); + EventResponse eventResponse = EventResponse.of(eventService.saveEvent(request.toAppRequest())); String jwtToken = authService.createToken(eventResponse.eventId()); From 1feb2d615789202b4b99de18ad63f604a8ad3561 Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Fri, 9 Aug 2024 11:49:14 +0900 Subject: [PATCH 131/178] =?UTF-8?q?refactor:=20=ED=96=89=EC=82=AC=20?= =?UTF-8?q?=EC=B0=B8=EC=97=AC=20=EC=9D=B8=EC=9B=90=20=EC=9D=B4=EB=A6=84=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20api=20=EC=88=98=EC=A0=95=20(#268)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 회원 이름 변경 api 여러명으로 추가 * style: 메소드 순서 변경 --- server/src/docs/asciidoc/event.adoc | 11 +- .../haengdong/application/EventService.java | 51 +++++-- .../request/MemberNameUpdateAppRequest.java | 7 + .../request/MemberNamesUpdateAppRequest.java | 8 ++ .../request/MemberUpdateAppRequest.java | 4 - .../exception/HaengdongErrorCode.java | 1 + .../presentation/EventController.java | 9 +- .../request/MemberNameUpdateRequest.java | 18 +++ .../request/MemberNamesUpdateRequest.java | 16 +++ .../request/MemberUpdateRequest.java | 15 -- .../application/EventServiceTest.java | 78 ++++++++++- .../docs/EventControllerDocsTest.java | 130 +++++++++--------- .../presentation/EventControllerTest.java | 13 +- 13 files changed, 256 insertions(+), 105 deletions(-) create mode 100644 server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/MemberNamesUpdateAppRequest.java delete mode 100644 server/src/main/java/server/haengdong/application/request/MemberUpdateAppRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/MemberNameUpdateRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java delete mode 100644 server/src/main/java/server/haengdong/presentation/request/MemberUpdateRequest.java diff --git a/server/src/docs/asciidoc/event.adoc b/server/src/docs/asciidoc/event.adoc index 253120e52..72511b91b 100644 --- a/server/src/docs/asciidoc/event.adoc +++ b/server/src/docs/asciidoc/event.adoc @@ -106,6 +106,15 @@ operation::updateEventMemberName[snippets="path-parameters,http-request,request- [source,json,options="nowrap"] ---- [ + + { + "code":"MEMBER_NAME_CHANGE_DUPLICATE", + "message":"중복된 참여 인원 이름 변경 요청이 존재합니다." + }, + { + "code":"MEMBER_NOT_EXIST", + "message":"현재 참여하고 있지 않는 인원이 존재합니다." + }, { "code":"REQUEST_EMPTY", "message":"멤버 이름은 공백일 수 없습니다." @@ -128,7 +137,7 @@ operation::updateEventMemberName[snippets="path-parameters,http-request,request- }, { "code":"TOKEN_EXPIRED", - "message":"토큰이 존재하지 않습니다." + "message":"만료된 토큰입니다." }, { "code":"TOKEN_INVALID", diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java index 3408a6215..57109a721 100644 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -3,12 +3,14 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.Set; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import server.haengdong.application.request.EventAppRequest; import server.haengdong.application.request.EventLoginAppRequest; -import server.haengdong.application.request.MemberUpdateAppRequest; +import server.haengdong.application.request.MemberNameUpdateAppRequest; +import server.haengdong.application.request.MemberNamesUpdateAppRequest; import server.haengdong.application.response.ActionAppResponse; import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; @@ -100,22 +102,55 @@ public MembersAppResponse findAllMembers(String token) { } @Transactional - public void updateMember(String token, String memberName, MemberUpdateAppRequest request) { + public void updateMember(String token, MemberNamesUpdateAppRequest request) { Event event = getEvent(token); - String updatedMemberName = request.name(); - validateMemberNameUnique(event, updatedMemberName); + List<MemberNameUpdateAppRequest> members = request.members(); - memberActionRepository.findAllByAction_EventAndMemberName(event, memberName) - .forEach(memberAction -> memberAction.updateMemberName(updatedMemberName)); + validateBeforeNames(members, event); + validateAfterNames(members, event); + + members.forEach(member -> updateMemberName(event, member.before(), member.after())); + } + + private void validateBeforeNames(List<MemberNameUpdateAppRequest> members, Event event) { + List<String> beforeNames = members.stream() + .map(MemberNameUpdateAppRequest::before) + .toList(); + if (beforeNames.size() != Set.copyOf(beforeNames).size()) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); + } + beforeNames.forEach(beforeName -> validateBeforeMemberNameExist(event, beforeName)); + } + + private void validateBeforeMemberNameExist(Event event, String beforeName) { + boolean isMemberNameExist = memberActionRepository.existsByAction_EventAndMemberName(event, beforeName); + if (!isMemberNameExist) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NOT_EXIST); + } + } + + private void validateAfterNames(List<MemberNameUpdateAppRequest> members, Event event) { + List<String> afterNames = members.stream() + .map(MemberNameUpdateAppRequest::after) + .toList(); + if (afterNames.size() != Set.copyOf(afterNames).size()) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); + } + afterNames.forEach(afterName -> validateAfterMemberNameNotExist(event, afterName)); } - private void validateMemberNameUnique(Event event, String updatedMemberName) { - boolean isMemberNameExist = memberActionRepository.existsByAction_EventAndMemberName(event, updatedMemberName); + private void validateAfterMemberNameNotExist(Event event, String afterName) { + boolean isMemberNameExist = memberActionRepository.existsByAction_EventAndMemberName(event, afterName); if (isMemberNameExist) { throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); } } + private void updateMemberName(Event event, String beforeName, String afterName) { + memberActionRepository.findAllByAction_EventAndMemberName(event, beforeName) + .forEach(memberAction -> memberAction.updateMemberName(afterName)); + } + public void validatePassword(EventLoginAppRequest request) throws HaengdongException { Event event = getEvent(request.token()); if (event.isSamePassword(request.password())) { diff --git a/server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java new file mode 100644 index 000000000..d629d3a02 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java @@ -0,0 +1,7 @@ +package server.haengdong.application.request; + +public record MemberNameUpdateAppRequest( + String before, + String after +) { +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberNamesUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberNamesUpdateAppRequest.java new file mode 100644 index 000000000..cd0c00544 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberNamesUpdateAppRequest.java @@ -0,0 +1,8 @@ +package server.haengdong.application.request; + +import java.util.List; + +public record MemberNamesUpdateAppRequest( + List<MemberNameUpdateAppRequest> members +) { +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberUpdateAppRequest.java deleted file mode 100644 index cbef9dda9..000000000 --- a/server/src/main/java/server/haengdong/application/request/MemberUpdateAppRequest.java +++ /dev/null @@ -1,4 +0,0 @@ -package server.haengdong.application.request; - -public record MemberUpdateAppRequest(String name) { -} diff --git a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java index bd0866d00..8af8d31e5 100644 --- a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java +++ b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java @@ -25,6 +25,7 @@ public enum HaengdongErrorCode { MEMBER_NAME_DUPLICATE("중복된 행사 참여 인원 이름이 존재합니다."), MEMBER_NOT_EXIST("현재 참여하고 있지 않는 인원이 존재합니다."), MEMBER_ALREADY_EXIST("현재 참여하고 있는 인원이 존재합니다."), + MEMBER_NAME_CHANGE_DUPLICATE("중복된 참여 인원 이름 변경 요청이 존재합니다."), MEMBER_ACTION_NOT_FOUND("존재하지 않는 멤버 액션입니다."), MEMBER_ACTION_STATUS_INVALID("멤버 액션은 IN, OUT만 가능합니다. 입력한 멤버 액션: %s"), diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java index 356d5216d..bbca6aa51 100644 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -18,7 +18,7 @@ import server.haengdong.infrastructure.auth.CookieProperties; import server.haengdong.presentation.request.EventLoginRequest; import server.haengdong.presentation.request.EventSaveRequest; -import server.haengdong.presentation.request.MemberUpdateRequest; +import server.haengdong.presentation.request.MemberNamesUpdateRequest; import server.haengdong.presentation.response.EventDetailResponse; import server.haengdong.presentation.response.EventResponse; import server.haengdong.presentation.response.MembersResponse; @@ -69,13 +69,12 @@ public ResponseEntity<MembersResponse> findAllMembers(@PathVariable("eventId") S return ResponseEntity.ok(response); } - @PutMapping("/api/events/{eventId}/members/{memberName}") + @PutMapping("/api/events/{eventId}/members/nameChange") public ResponseEntity<Void> updateMember( @PathVariable("eventId") String token, - @PathVariable("memberName") String memberName, - @Valid @RequestBody MemberUpdateRequest request + @Valid @RequestBody MemberNamesUpdateRequest request ) { - eventService.updateMember(token, memberName, request.toAppRequest()); + eventService.updateMember(token, request.toAppRequest()); return ResponseEntity.ok().build(); } diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberNameUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberNameUpdateRequest.java new file mode 100644 index 000000000..3cd2294ca --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MemberNameUpdateRequest.java @@ -0,0 +1,18 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import server.haengdong.application.request.MemberNameUpdateAppRequest; + +public record MemberNameUpdateRequest( + + @NotBlank(message = "멤버 이름은 공백일 수 없습니다.") + String before, + + @NotBlank(message = "멤버 이름은 공백일 수 없습니다.") + String after +) { + + public MemberNameUpdateAppRequest toAppRequest() { + return new MemberNameUpdateAppRequest(before, after); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java new file mode 100644 index 000000000..c67e1b699 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java @@ -0,0 +1,16 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.Valid; +import java.util.List; +import server.haengdong.application.request.MemberNamesUpdateAppRequest; + +public record MemberNamesUpdateRequest( + @Valid List<MemberNameUpdateRequest> members +) { + + public MemberNamesUpdateAppRequest toAppRequest() { + return new MemberNamesUpdateAppRequest(members.stream() + .map(MemberNameUpdateRequest::toAppRequest) + .toList()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberUpdateRequest.java deleted file mode 100644 index 412457750..000000000 --- a/server/src/main/java/server/haengdong/presentation/request/MemberUpdateRequest.java +++ /dev/null @@ -1,15 +0,0 @@ -package server.haengdong.presentation.request; - -import jakarta.validation.constraints.NotBlank; -import server.haengdong.application.request.MemberUpdateAppRequest; - -public record MemberUpdateRequest( - - @NotBlank(message = "멤버 이름은 공백일 수 없습니다.") - String name -) { - - public MemberUpdateAppRequest toAppRequest() { - return new MemberUpdateAppRequest(name); - } -} diff --git a/server/src/test/java/server/haengdong/application/EventServiceTest.java b/server/src/test/java/server/haengdong/application/EventServiceTest.java index f5694efa1..407fa1457 100644 --- a/server/src/test/java/server/haengdong/application/EventServiceTest.java +++ b/server/src/test/java/server/haengdong/application/EventServiceTest.java @@ -14,7 +14,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.MockBean; import server.haengdong.application.request.EventAppRequest; -import server.haengdong.application.request.MemberUpdateAppRequest; +import server.haengdong.application.request.MemberNameUpdateAppRequest; +import server.haengdong.application.request.MemberNamesUpdateAppRequest; import server.haengdong.application.response.ActionAppResponse; import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; @@ -119,7 +120,7 @@ void findAllMembersTest() { assertThat(membersAppResponse.memberNames()).containsExactlyInAnyOrder("토다리", "쿠키"); } - @DisplayName("행사 참여 인원의 이름을 변경한다.") + @DisplayName("행사 참여 인원들의 이름을 변경한다.") @Test void updateMember() { Event event = Fixture.EVENT1; @@ -134,13 +135,16 @@ void updateMember() { memberAction1, memberAction2, memberAction3, memberAction4, memberAction5, memberAction6 )); - eventService.updateMember(event.getToken(), "쿠키", new MemberUpdateAppRequest("쿡쿡")); + eventService.updateMember(event.getToken(), new MemberNamesUpdateAppRequest(List.of( + new MemberNameUpdateAppRequest("쿠키", "쿡쿡"), + new MemberNameUpdateAppRequest("토다리", "토쟁이") + ))); List<MemberAction> foundMemberActions = memberActionRepository.findAllByEvent(event); assertThat(foundMemberActions) .extracting(MemberAction::getId, MemberAction::getMemberName) .contains( - tuple(memberAction1.getId(), "토다리"), + tuple(memberAction1.getId(), "토쟁이"), tuple(memberAction2.getId(), "쿡쿡"), tuple(memberAction3.getId(), "웨디"), tuple(memberAction4.getId(), "쿡쿡"), @@ -149,7 +153,7 @@ void updateMember() { ); } - @DisplayName("참여 인원 이름을 이미 존재하는 행사 참여 인원과 동일한 이름으로 변경할 수 없다.") + @DisplayName("이미 존재하는 인원의 이름으로 변경할 수 없다.") @Test void updateMember1() { Event event = Fixture.EVENT1; @@ -159,7 +163,69 @@ void updateMember1() { eventRepository.save(event); memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); - assertThatThrownBy(() -> eventService.updateMember(event.getToken(), "쿠키", new MemberUpdateAppRequest("토다리"))) + MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( + new MemberNameUpdateAppRequest("쿠키", "쿡쿡"), + new MemberNameUpdateAppRequest("웨디", "토다리") + )); + + assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("존재하지 않는 인원은 변경할 수 없다.") + @Test + void updateMember2() { + Event event = Fixture.EVENT1; + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "토다리", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "쿠키", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "웨디", IN, 2L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); + + MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( + new MemberNameUpdateAppRequest("쿡쿡", "토쟁이"), + new MemberNameUpdateAppRequest("웨디", "말복") + )); + + assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("변경 전 참여 인원 이름이 중복될 수 없다.") + @Test + void updateMember3() { + Event event = Fixture.EVENT1; + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "토다리", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "쿠키", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "웨디", IN, 2L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); + + MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( + new MemberNameUpdateAppRequest("쿠키", "쿡쿡"), + new MemberNameUpdateAppRequest("쿠키", "토쟁이") + )); + + assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("변경 후 참여 인원 이름이 중복될 수 없다.") + @Test + void updateMember4() { + Event event = Fixture.EVENT1; + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "토다리", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "쿠키", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "웨디", IN, 2L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); + + MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( + new MemberNameUpdateAppRequest("쿠키", "쿡쿡"), + new MemberNameUpdateAppRequest("토다리", "쿡쿡") + )); + + assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) .isInstanceOf(HaengdongException.class); } } diff --git a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java index 67095aae9..fef6ce106 100644 --- a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java @@ -44,7 +44,8 @@ import server.haengdong.presentation.EventController; import server.haengdong.presentation.request.EventLoginRequest; import server.haengdong.presentation.request.EventSaveRequest; -import server.haengdong.presentation.request.MemberUpdateRequest; +import server.haengdong.presentation.request.MemberNameUpdateRequest; +import server.haengdong.presentation.request.MemberNamesUpdateRequest; public class EventControllerDocsTest extends RestDocsSupport { @@ -135,15 +136,15 @@ void findAllMembersTest() throws Exception { .andExpect(jsonPath("$.memberNames[1]").value("쿠키")) .andDo( document("findAllEventMember", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - responseFields( - fieldWithPath("memberNames").type(JsonFieldType.ARRAY) - .description("행사 참여자 목록") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("memberNames").type(JsonFieldType.ARRAY) + .description("행사 참여자 목록") + ) ) ); } @@ -152,29 +153,34 @@ void findAllMembersTest() throws Exception { @Test void updateMember() throws Exception { String token = "TOKEN"; - MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest("변경된 이름"); - String requestBody = objectMapper.writeValueAsString(memberUpdateRequest); + MemberNamesUpdateRequest memberNameUpdateRequest = new MemberNamesUpdateRequest(List.of( + new MemberNameUpdateRequest("토다링", "토쟁이"), + new MemberNameUpdateRequest("감자", "고구마") + )); - mockMvc.perform(put("/api/events/{eventId}/members/{memberName}", token, "변경 전 이름") - .cookie(EVENT_COOKIE) - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + String requestBody = objectMapper.writeValueAsString(memberNameUpdateRequest); + + mockMvc.perform(put("/api/events/{eventId}/members/nameChange", token) + .cookie(EVENT_COOKIE) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) .andDo(print()) .andExpect(status().isOk()) .andDo( document("updateEventMemberName", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID"), - parameterWithName("memberName").description("참여자 이름") - ), - requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") - ), - requestFields( - fieldWithPath("name").type(JsonFieldType.STRING).description("수정할 참여자 이름") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), + requestFields( + fieldWithPath("members").type(JsonFieldType.ARRAY).description("수정할 참여자 목록"), + fieldWithPath("members[].before").type(JsonFieldType.STRING).description("수정 전 참여자 이름"), + fieldWithPath("members[].after").type(JsonFieldType.STRING).description("수정 후 참여자 이름") + ) ) ); } @@ -189,25 +195,25 @@ void loginEvent() throws Exception { given(authService.getTokenName()).willReturn("eventToken"); mockMvc.perform(post("/api/events/{eventId}/login", token) - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) .andDo(print()) .andExpect(cookie().value("eventToken", "jwtToken")) .andExpect(status().isOk()) .andDo( document("eventLogin", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - requestFields( - fieldWithPath("password").type(JsonFieldType.STRING) - .description("행사 비밀 번호") - ), - responseCookies( - cookieWithName("eventToken").description("행사 관리자용 토큰") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestFields( + fieldWithPath("password").type(JsonFieldType.STRING) + .description("행사 비밀 번호") + ), + responseCookies( + cookieWithName("eventToken").description("행사 관리자용 토큰") + ) ) ); } @@ -225,7 +231,7 @@ void findActions() throws Exception { given(eventService.findActions(token)).willReturn(actionAppResponses); mockMvc.perform(get("/api/events/{eventId}/actions", token) - .accept(MediaType.APPLICATION_JSON)) + .accept(MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) .andExpect(jsonPath("$.steps[0].type").value(equalTo("IN"))) @@ -255,25 +261,25 @@ void findActions() throws Exception { .andDo( document("findActions", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - responseFields( - fieldWithPath("steps[].type").type(JsonFieldType.STRING) - .description("액션 유형 [BILL, IN, OUT]"), - fieldWithPath("steps[].members").type(JsonFieldType.ARRAY) - .description("해당 step에 참여한 참여자 목록"), - fieldWithPath("steps[].actions[].actionId").type(JsonFieldType.NUMBER) - .description("액션 ID"), - fieldWithPath("steps[].actions[].name").type(JsonFieldType.STRING) - .description("참여자 액션일 경우 참여자 이름, 지출 액션일 경우 지출 내역 이름"), - fieldWithPath("steps[].actions[].price").type(JsonFieldType.NUMBER).optional() - .description("참여자 액션일 경우 null, 지출 액션일 경우 지출 금액"), - fieldWithPath("steps[].actions[].sequence").type(JsonFieldType.NUMBER) - .description("액션 순서") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("steps[].type").type(JsonFieldType.STRING) + .description("액션 유형 [BILL, IN, OUT]"), + fieldWithPath("steps[].members").type(JsonFieldType.ARRAY) + .description("해당 step에 참여한 참여자 목록"), + fieldWithPath("steps[].actions[].actionId").type(JsonFieldType.NUMBER) + .description("액션 ID"), + fieldWithPath("steps[].actions[].name").type(JsonFieldType.STRING) + .description("참여자 액션일 경우 참여자 이름, 지출 액션일 경우 지출 내역 이름"), + fieldWithPath("steps[].actions[].price").type(JsonFieldType.NUMBER).optional() + .description("참여자 액션일 경우 null, 지출 액션일 경우 지출 금액"), + fieldWithPath("steps[].actions[].sequence").type(JsonFieldType.NUMBER) + .description("액션 순서") + ) ) ); } diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java index 4ba7bc4a9..fcfe48d01 100644 --- a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java @@ -21,7 +21,8 @@ import server.haengdong.application.response.MembersAppResponse; import server.haengdong.presentation.request.EventLoginRequest; import server.haengdong.presentation.request.EventSaveRequest; -import server.haengdong.presentation.request.MemberUpdateRequest; +import server.haengdong.presentation.request.MemberNameUpdateRequest; +import server.haengdong.presentation.request.MemberNamesUpdateRequest; class EventControllerTest extends ControllerTestSupport { @@ -77,10 +78,14 @@ void findAllMembersTest() throws Exception { @Test void updateMember() throws Exception { String token = "TOKEN"; - MemberUpdateRequest memberUpdateRequest = new MemberUpdateRequest("변경된 이름"); - String requestBody = objectMapper.writeValueAsString(memberUpdateRequest); + MemberNamesUpdateRequest memberNameUpdateRequest = new MemberNamesUpdateRequest(List.of( + new MemberNameUpdateRequest("토다링", "토쟁이"), + new MemberNameUpdateRequest("감자", "고구마") + )); - mockMvc.perform(put("/api/events/{eventId}/members/{memberName}", token, "변경 전 이름") + String requestBody = objectMapper.writeValueAsString(memberNameUpdateRequest); + + mockMvc.perform(put("/api/events/{eventId}/members/nameChange", token) .contentType(MediaType.APPLICATION_JSON) .content(requestBody)) .andDo(print()) From 921410d9fa96efd17faa0c74a5af866c39b7df19 Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Fri, 9 Aug 2024 16:51:10 +0900 Subject: [PATCH 132/178] =?UTF-8?q?fix:=20rest=20docs=20=EC=A0=80=EC=9E=A5?= =?UTF-8?q?=20=ED=8C=8C=EC=9D=BC=20=EC=9C=84=EC=B9=98=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=20(#273)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/build.gradle | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/server/build.gradle b/server/build.gradle index deb550da4..4229de130 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -51,7 +51,7 @@ ext { snippetsDir = file('build/generated-snippets') } -tasks.named('test') { +test { useJUnitPlatform() outputs.dir snippetsDir } @@ -59,23 +59,28 @@ tasks.named('test') { asciidoctor { inputs.dir snippetsDir configurations 'asciidoctorExt' - dependsOn test baseDirFollowsSourceFile() + dependsOn test +} + +tasks.resolveMainClassName { + dependsOn 'copyApiDocuments' } tasks.register('copyApiDocuments', Copy) { - doFirst { - delete file('src/main/resources/static/docs') - } dependsOn asciidoctor from file("build/docs/asciidoc") - into file("src/main/resources/static/docs") + into file("build/resources/main/static/docs") } bootJar { dependsOn copyApiDocuments } +jar { + enabled = false +} + build { dependsOn copyApiDocuments } From 63fbbc9c8aacfe6a4dcb9a0f54f9a7bc23baefd5 Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Fri, 9 Aug 2024 18:31:00 +0900 Subject: [PATCH 133/178] =?UTF-8?q?fix:=20=EC=96=B4=EB=93=9C=EB=AF=BC=20?= =?UTF-8?q?=EA=B6=8C=ED=95=9C=20=ED=99=95=EC=9D=B8=20=EB=B6=88=EA=B0=80=20?= =?UTF-8?q?=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95=20(#275)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/server/haengdong/presentation/EventController.java | 2 +- .../java/server/haengdong/docs/EventControllerDocsTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java index bbca6aa51..0f181c2db 100644 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -93,7 +93,7 @@ public ResponseEntity<Void> loginEvent( .build(); } - @GetMapping("/api/events/{eventId}/auth") + @PostMapping("/api/events/{eventId}/auth") public ResponseEntity<Void> authenticate(@PathVariable("eventId") String token) { return ResponseEntity.ok().build(); } diff --git a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java index fef6ce106..09546bcc3 100644 --- a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java @@ -288,7 +288,7 @@ void findActions() throws Exception { @Test void authenticateTest() throws Exception { String token = "TOKEN"; - mockMvc.perform(get("/api/events/{eventId}/auth", token) + mockMvc.perform(post("/api/events/{eventId}/auth", token) .cookie(EVENT_COOKIE)) .andDo(print()) .andExpect(status().isOk()) From a8c9d0166aea140d4020dfb134a81389b721be9a Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Fri, 9 Aug 2024 18:37:12 +0900 Subject: [PATCH 134/178] =?UTF-8?q?fix:=20=ED=96=89=EC=82=AC=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EB=B6=88=EA=B0=80=20=EB=B2=84=EA=B7=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#283)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/server/haengdong/application/EventService.java | 2 +- .../main/java/server/haengdong/config/AdminInterceptor.java | 6 ++++++ .../src/main/java/server/haengdong/domain/event/Event.java | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java index 57109a721..3d2400372 100644 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -153,7 +153,7 @@ private void updateMemberName(Event event, String beforeName, String afterName) public void validatePassword(EventLoginAppRequest request) throws HaengdongException { Event event = getEvent(request.token()); - if (event.isSamePassword(request.password())) { + if (event.isNotSamePassword(request.password())) { throw new AuthenticationException(HaengdongErrorCode.PASSWORD_INVALID); } } diff --git a/server/src/main/java/server/haengdong/config/AdminInterceptor.java b/server/src/main/java/server/haengdong/config/AdminInterceptor.java index af24b783b..bb5e299f6 100644 --- a/server/src/main/java/server/haengdong/config/AdminInterceptor.java +++ b/server/src/main/java/server/haengdong/config/AdminInterceptor.java @@ -25,6 +25,12 @@ public AdminInterceptor(AuthService authService, AuthenticationExtractor authent public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { log.trace("login request = {}", request.getRequestURI()); + String requestURI = request.getRequestURI(); + + if (requestURI.endsWith("/login")) { + return true; // 요청을 계속 진행하도록 허용 + } + HttpMethod method = HttpMethod.valueOf(request.getMethod()); if (HttpMethod.GET.equals(method) || HttpMethod.OPTIONS.equals(method)) { return true; diff --git a/server/src/main/java/server/haengdong/domain/event/Event.java b/server/src/main/java/server/haengdong/domain/event/Event.java index e90becb3c..cd576a967 100644 --- a/server/src/main/java/server/haengdong/domain/event/Event.java +++ b/server/src/main/java/server/haengdong/domain/event/Event.java @@ -71,7 +71,7 @@ public boolean isTokenMismatch(String token) { return !this.token.equals(token); } - public boolean isSamePassword(String password) { - return this.password.equals(password); + public boolean isNotSamePassword(String password) { + return !this.password.equals(password); } } From f54b8258bb71d35f6e2ab6676a50247b1e023098 Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Mon, 12 Aug 2024 15:20:06 +0900 Subject: [PATCH 135/178] =?UTF-8?q?fix:=20CI/CD=20=ED=8A=B8=EB=A6=AC?= =?UTF-8?q?=EA=B1=B0=20=EC=A1=B0=EA=B1=B4=EC=97=90=EC=84=9C=20server=20?= =?UTF-8?q?=ED=8F=B4=EB=8D=94=20=EC=A1=B0=EA=B1=B4=20=EC=A0=9C=EA=B1=B0=20?= =?UTF-8?q?=20(#308)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: CI 트리거 조건을 수정 * feat: be-dev CD 트리거 조건에서 server 폴더 제거 --- .github/workflows/backend-dev.yml | 2 -- .github/workflows/backend-pull-request.yml | 2 -- 2 files changed, 4 deletions(-) diff --git a/.github/workflows/backend-dev.yml b/.github/workflows/backend-dev.yml index 4494c494f..331b3e8a6 100644 --- a/.github/workflows/backend-dev.yml +++ b/.github/workflows/backend-dev.yml @@ -3,8 +3,6 @@ name: backend-push on: push: branches: [ "be-dev" ] - paths: - - 'server/**' jobs: build: diff --git a/.github/workflows/backend-pull-request.yml b/.github/workflows/backend-pull-request.yml index 2d7becbfc..df008fd97 100644 --- a/.github/workflows/backend-pull-request.yml +++ b/.github/workflows/backend-pull-request.yml @@ -3,8 +3,6 @@ name: backend-pull-request on: pull_request: branches: [ "main", "be-dev" ] - paths: - - 'server/**' jobs: build: From 12485ef1deb3679a7120ff92a19b86982ce60273 Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Mon, 12 Aug 2024 15:43:30 +0900 Subject: [PATCH 136/178] =?UTF-8?q?feat:=20pr=20=EB=A8=B8=EC=A7=80?= =?UTF-8?q?=EC=8B=9C=20issue=20close=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(#309)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pr-issue-close.yml | 36 ++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/pr-issue-close.yml diff --git a/.github/workflows/pr-issue-close.yml b/.github/workflows/pr-issue-close.yml new file mode 100644 index 000000000..91e43e206 --- /dev/null +++ b/.github/workflows/pr-issue-close.yml @@ -0,0 +1,36 @@ +name: Close Issue on PR Merge + +on: + pull_request: + types: [closed] + +jobs: + close-issue: + if: github.event.pull_request.merged == true + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Extract issue number from PR body + id: extract_issue + run: | + # Fetch PR body + PR_BODY=$(curl -s -H "Authorization: token ${{ secrets.CONFIG_SUBMODULE_TOKEN }}" \ + "https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}" \ + | jq -r '.body') + + # Extract issue number from PR body using regex (customize if needed) + ISSUE_NUMBER=$(echo "$PR_BODY" | grep -oP '#\d+' | head -1 | sed 's/#//') + + echo "ISSUE_NUMBER=$ISSUE_NUMBER" >> $GITHUB_ENV + + - name: Close associated issue + if: env.ISSUE_NUMBER != '' + run: | + echo "Closing issue #${{ env.ISSUE_NUMBER }}" + curl -s -X PATCH -H "Authorization: token ${{ secrets.CONFIG_SUBMODULE_TOKEN }}" \ + -H "Accept: application/vnd.github.v3+json" \ + -d '{"state": "closed"}' \ + "https://api.github.com/repos/${{ github.repository }}/issues/${{ env.ISSUE_NUMBER }}" From 15ab738560d2f7ff52e2c3ce701b0af2a80f21cb Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Mon, 12 Aug 2024 15:47:58 +0900 Subject: [PATCH 137/178] =?UTF-8?q?refactor:=20yml,=20Dockerfile=20TZ=20As?= =?UTF-8?q?ia/Seoul=20=EC=A0=81=EC=9A=A9=20(#305)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Arachne <66822642+Arachneee@users.noreply.github.com> --- server/Dockerfile | 2 +- server/src/main/resources/application.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/server/Dockerfile b/server/Dockerfile index ae8c9c880..df2cf44e0 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -6,4 +6,4 @@ COPY /build/libs/*.jar /app/haengdong-0.0.1-SNAPSHOT.jar EXPOSE 8080 ENTRYPOINT ["java"] -CMD ["-Dspring.profiles.active=${SPRING_PROFILES_ACTIVE}", "-jar", "haengdong-0.0.1-SNAPSHOT.jar"] +CMD ["-Dspring.profiles.active=${SPRING_PROFILES_ACTIVE}", "-Duser.timezone=Asia/Seoul", "-jar", "haengdong-0.0.1-SNAPSHOT.jar"] diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index 425a2c5a0..a7ad1efd3 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -16,6 +16,7 @@ spring: properties: hibernate: format_sql: true + jdbc.time_zone: Asia/Seoul show-sql: true cors: From 85add2dd4d7e71739330b783ed608cd5047de75b Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Mon, 12 Aug 2024 16:13:55 +0900 Subject: [PATCH 138/178] =?UTF-8?q?refactor:=20actuator=20health=20?= =?UTF-8?q?=EC=97=94=EB=93=9C=ED=8F=AC=EC=9D=B8=ED=8A=B8=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EB=B3=80=EA=B2=BD=20(#303)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: actuator health 엔드포인트 설정 변경 * refactor: AdminInterceptor log level 변경 --------- Co-authored-by: Juhwan Kim <13selfesteem91@naver.com> --- .../haengdong/HaengdongApplication.java | 1 - .../haengdong/config/AdminInterceptor.java | 2 +- .../exception/GlobalExceptionHandler.java | 20 ++++++++++++++----- .../exception/HaengdongErrorCode.java | 1 + .../presentation/EventController.java | 2 -- server/src/main/resources/application.yml | 2 +- server/src/main/resources/logback-spring.xml | 3 ++- 7 files changed, 20 insertions(+), 11 deletions(-) diff --git a/server/src/main/java/server/haengdong/HaengdongApplication.java b/server/src/main/java/server/haengdong/HaengdongApplication.java index 0072a5a11..4a84c6120 100644 --- a/server/src/main/java/server/haengdong/HaengdongApplication.java +++ b/server/src/main/java/server/haengdong/HaengdongApplication.java @@ -9,7 +9,6 @@ public class HaengdongApplication { public static void main(String[] args) { - log.error("################### 안녕하세요. CI/CD 테스트입니다. ###################"); SpringApplication.run(HaengdongApplication.class, args); } diff --git a/server/src/main/java/server/haengdong/config/AdminInterceptor.java b/server/src/main/java/server/haengdong/config/AdminInterceptor.java index bb5e299f6..c78cd854e 100644 --- a/server/src/main/java/server/haengdong/config/AdminInterceptor.java +++ b/server/src/main/java/server/haengdong/config/AdminInterceptor.java @@ -23,7 +23,7 @@ public AdminInterceptor(AuthService authService, AuthenticationExtractor authent @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { - log.trace("login request = {}", request.getRequestURI()); + log.debug("login request = {}", request.getRequestURI()); String requestURI = request.getRequestURI(); diff --git a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java index 026ee3452..7ed01c3c6 100644 --- a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java +++ b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java @@ -17,25 +17,35 @@ public class GlobalExceptionHandler { @ExceptionHandler(AuthenticationException.class) public ResponseEntity<ErrorResponse> authenticationException(AuthenticationException e) { + log.warn(e.getMessage(), e); return ResponseEntity.status(HttpStatus.UNAUTHORIZED) .body(ErrorResponse.of(e.getErrorCode())); } - @ExceptionHandler({HttpRequestMethodNotSupportedException.class, NoResourceFoundException.class}) - public ResponseEntity<ErrorResponse> noResourceException() { + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + public ResponseEntity<ErrorResponse> noResourceException(HttpRequestMethodNotSupportedException e) { + log.warn(e.getMessage(), e); + return ResponseEntity.badRequest() + .body(ErrorResponse.of(HaengdongErrorCode.REQUEST_METHOD_NOT_SUPPORTED)); + } + + @ExceptionHandler(NoResourceFoundException.class) + public ResponseEntity<ErrorResponse> noResourceException(NoResourceFoundException e) { + log.warn(e.getMessage(), e); return ResponseEntity.badRequest() .body(ErrorResponse.of(HaengdongErrorCode.NO_RESOURCE_REQUEST)); } @ExceptionHandler(HttpMessageNotReadableException.class) - public ResponseEntity<ErrorResponse> httpMessageNotReadableException() { + public ResponseEntity<ErrorResponse> httpMessageNotReadableException(HttpMessageNotReadableException e) { + log.warn(e.getMessage(), e); return ResponseEntity.badRequest() .body(ErrorResponse.of(HaengdongErrorCode.MESSAGE_NOT_READABLE)); } @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<ErrorResponse> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { - log.info(e.getMessage(), e); + log.warn(e.getMessage(), e); String errorMessage = e.getFieldErrors().stream() .map(error -> error.getField() + " " + error.getDefaultMessage()) .collect(Collectors.joining(", ")); @@ -46,7 +56,7 @@ public ResponseEntity<ErrorResponse> handleMethodArgumentNotValidException(Metho @ExceptionHandler(HaengdongException.class) public ResponseEntity<ErrorResponse> haengdongException(HaengdongException e) { - log.info(e.getMessage(), e); + log.warn(e.getMessage(), e); return ResponseEntity.badRequest() .body(ErrorResponse.of(e.getErrorCode())); } diff --git a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java index 8af8d31e5..4020879d2 100644 --- a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java +++ b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java @@ -53,6 +53,7 @@ public enum HaengdongErrorCode { /* System */, MESSAGE_NOT_READABLE("읽을 수 없는 요청입니다."), + REQUEST_METHOD_NOT_SUPPORTED("지원하지 않는 요청 메서드입니다."), NO_RESOURCE_REQUEST("존재하지 않는 자원입니다."), INTERNAL_SERVER_ERROR("서버 내부에서 에러가 발생했습니다."); diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java index 0f181c2db..54de966e5 100644 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -36,8 +36,6 @@ public class EventController { @PostMapping("/api/events") public ResponseEntity<EventResponse> saveEvent(@Valid @RequestBody EventSaveRequest request) { - log.error("################### 안녕하세요. CI/CD 테스트입니다. ###################"); - EventResponse eventResponse = EventResponse.of(eventService.saveEvent(request.toAppRequest())); String jwtToken = authService.createToken(eventResponse.eventId()); diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index a7ad1efd3..6a8bd77af 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -40,7 +40,7 @@ management: endpoints: web: exposure: - include: logfile, metrics + include: health, metrics, logfile logging: level: diff --git a/server/src/main/resources/logback-spring.xml b/server/src/main/resources/logback-spring.xml index 204130e8c..7fa3da153 100644 --- a/server/src/main/resources/logback-spring.xml +++ b/server/src/main/resources/logback-spring.xml @@ -6,7 +6,8 @@ <maxHistory>30</maxHistory> </rollingPolicy> <encoder> - <pattern>%d{yyyy-MM-dd HH:mm:ss} - %msg%n</pattern> + <!-- 날짜, 시간, 로그 레벨, 스레드 이름, 로거 이름, 메시지 형식 --> + <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> From be83b89e8bbb6d380ed60fe85a2b3b20cd88585e Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Mon, 12 Aug 2024 16:40:19 +0900 Subject: [PATCH 139/178] =?UTF-8?q?feat:=20=EC=84=9C=EB=B2=84=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=20=EB=B3=BC=EB=A5=A8=20=EB=A7=88=EC=9A=B4=ED=8A=B8=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20(#300)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 로그 파일 볼륨 설정 * feat: 볼륨 이름 지정 --- .github/workflows/backend-dev.yml | 2 +- .github/workflows/backend-prod.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/backend-dev.yml b/.github/workflows/backend-dev.yml index 331b3e8a6..a3257f028 100644 --- a/.github/workflows/backend-dev.yml +++ b/.github/workflows/backend-dev.yml @@ -69,4 +69,4 @@ jobs: run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }} - name: Docker run - run: sudo docker run -d -p 8080:8080 -e SPRING_PROFILES_ACTIVE=dev --name haengdong-backend ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }} + run: sudo docker run -d -p 8080:8080 -e SPRING_PROFILES_ACTIVE=dev -v log-volume:/app/logs --name haengdong-backend ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }} diff --git a/.github/workflows/backend-prod.yml b/.github/workflows/backend-prod.yml index ffc0b771a..f7daacd33 100644 --- a/.github/workflows/backend-prod.yml +++ b/.github/workflows/backend-prod.yml @@ -71,4 +71,4 @@ jobs: run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }} - name: Docker run - run: sudo docker run -d -p 8080:8080 -e SPRING_PROFILES_ACTIVE=prod --name haengdong-backend ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }} + run: sudo docker run -d -p 8080:8080 -e SPRING_PROFILES_ACTIVE=prod -v log-volume:/app/logs --name haengdong-backend ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }} From 901c25acf8b383798d882c74b7a85ceaccdc3f3c Mon Sep 17 00:00:00 2001 From: Juhwan Kim <13selfesteem91@naver.com> Date: Tue, 13 Aug 2024 10:27:32 +0900 Subject: [PATCH 140/178] =?UTF-8?q?feat:=20LogBack=20=EB=A1=A4=EB=A7=81=20?= =?UTF-8?q?=EC=A0=95=EC=B1=85=20=EC=88=98=EC=A0=95,=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=20=EB=A0=88=EB=B2=A8=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=20(#332)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Logback 로그 레벨 분리 * feat: Lockback 로그 레벨 분리 --------- Co-authored-by: Arachneee <jhg2819@naver.com> --- server/src/main/resources/application.yml | 12 --- server/src/main/resources/config | 2 +- server/src/main/resources/logback-spring.xml | 88 ++++++++++++++++++-- 3 files changed, 81 insertions(+), 21 deletions(-) diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index 6a8bd77af..2ae503547 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -42,17 +42,6 @@ management: exposure: include: health, metrics, logfile -logging: - level: - root: debug - org.springframework.web: debug - server.haengdong: debug - - file: - name: logs/spring-boot-application.log - path: logs - config: classpath:logback-spring.xml - server: servlet: encoding: @@ -75,4 +64,3 @@ spring: import: classpath:config/application-dev.yml activate: on-profile: dev - diff --git a/server/src/main/resources/config b/server/src/main/resources/config index 13959710c..141eb40e8 160000 --- a/server/src/main/resources/config +++ b/server/src/main/resources/config @@ -1 +1 @@ -Subproject commit 13959710cc6d19309aafbc87681d25b9060d935d +Subproject commit 141eb40e871cc9c3e172af46db29d90ac6448180 diff --git a/server/src/main/resources/logback-spring.xml b/server/src/main/resources/logback-spring.xml index 7fa3da153..12e5940d4 100644 --- a/server/src/main/resources/logback-spring.xml +++ b/server/src/main/resources/logback-spring.xml @@ -1,8 +1,71 @@ <configuration> - <appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"> - <file>logs/spring-boot-application.log</file> + <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <!-- 콘솔에 로그 출력 형식 --> + <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <appender name="ERROR-ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>ERROR</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + <file>logs/spring-boot-application-error.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>logs/spring-boot-application-error.%d{yyyy-MM-dd}.log</fileNamePattern> + <maxHistory>30</maxHistory> + </rollingPolicy> + <encoder> + <!-- 날짜, 시간, 로그 레벨, 스레드 이름, 로거 이름, 메시지 형식 --> + <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <appender name="WARN-ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>WARN</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + <file>logs/spring-boot-application-warn.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>logs/spring-boot-application-warn.%d{yyyy-MM-dd}.log</fileNamePattern> + <maxHistory>30</maxHistory> + </rollingPolicy> + <encoder> + <!-- 날짜, 시간, 로그 레벨, 스레드 이름, 로거 이름, 메시지 형식 --> + <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <appender name="INFO-ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>INFO</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + <file>logs/spring-boot-application-info.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>logs/spring-boot-application-info.%d{yyyy-MM-dd}.log</fileNamePattern> + <maxHistory>30</maxHistory> + </rollingPolicy> + <encoder> + <!-- 날짜, 시간, 로그 레벨, 스레드 이름, 로거 이름, 메시지 형식 --> + <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <appender name="DEBUG-ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>DEBUG</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + <file>logs/spring-boot-application-debug.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> - <fileNamePattern>logs/spring-boot-application.%d{yyyy-MM-dd}.log</fileNamePattern> + <fileNamePattern>logs/spring-boot-application-debug.%d{yyyy-MM-dd}.log</fileNamePattern> <maxHistory>30</maxHistory> </rollingPolicy> <encoder> @@ -11,10 +74,19 @@ </encoder> </appender> - <root level="INFO"> - <appender-ref ref="ROLLING"/> - </root> + <springProfile name="default"> + <root level="INFO"> + <appender-ref ref="CONSOLE"/> + </root> + </springProfile> - <logger name="org.springframework.web" level="DEBUG"/> - <logger name="server.haengdong" level="DEBUG"/> + <springProfile name="default"> + <root level="INFO"> + <appender-ref ref="CONSOLE"/> + <appender-ref ref="ERROR-ROLLING"/> + <appender-ref ref="WARN-ROLLING"/> + <appender-ref ref="INFO-ROLLING"/> + <appender-ref ref="DEBUG-ROLLING"/> + </root> + </springProfile> </configuration> From b8fc84e9b20e1181591139628820bb7504cd4030 Mon Sep 17 00:00:00 2001 From: Juhwan Kim <13selfesteem91@naver.com> Date: Tue, 13 Aug 2024 10:55:27 +0900 Subject: [PATCH 141/178] =?UTF-8?q?fix:=20=EC=84=9C=EB=B8=8C=20=EB=AA=A8?= =?UTF-8?q?=EB=93=88=20=ED=94=84=EB=A1=9C=ED=8C=8C=EC=9D=BC=20=EC=98=A4?= =?UTF-8?q?=ED=83=80=20=EC=88=98=EC=A0=95=20(#334)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/main/resources/logback-spring.xml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/server/src/main/resources/logback-spring.xml b/server/src/main/resources/logback-spring.xml index 12e5940d4..283b966a3 100644 --- a/server/src/main/resources/logback-spring.xml +++ b/server/src/main/resources/logback-spring.xml @@ -80,13 +80,18 @@ </root> </springProfile> - <springProfile name="default"> + <springProfile name="dev"> <root level="INFO"> - <appender-ref ref="CONSOLE"/> <appender-ref ref="ERROR-ROLLING"/> <appender-ref ref="WARN-ROLLING"/> <appender-ref ref="INFO-ROLLING"/> <appender-ref ref="DEBUG-ROLLING"/> </root> </springProfile> + + <springProfile name="prod"> + <root level="ERROR"> + <appender-ref ref="ERROR-ROLLING"/> + </root> + </springProfile> </configuration> From 469553267fa0025b8dd23cbf578f8cd7453d63e2 Mon Sep 17 00:00:00 2001 From: JUHA <84626225+khabh@users.noreply.github.com> Date: Fri, 16 Aug 2024 10:56:51 +0900 Subject: [PATCH 142/178] =?UTF-8?q?refactor:=20=ED=98=84=EC=9E=AC=20?= =?UTF-8?q?=EC=B0=B8=EC=97=AC=20=EC=9D=B8=EC=9B=90=20=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20API=20=EB=B0=98=ED=99=98=20=ED=98=95?= =?UTF-8?q?=EC=8B=9D=20=EC=88=98=EC=A0=95=20(#361)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/response/CurrentMemberResponse.java | 10 ---------- .../presentation/response/CurrentMembersResponse.java | 6 +++--- .../haengdong/docs/MemberActionControllerDocsTest.java | 10 ++++------ .../presentation/MemberActionControllerTest.java | 4 ++-- 4 files changed, 9 insertions(+), 21 deletions(-) delete mode 100644 server/src/main/java/server/haengdong/presentation/response/CurrentMemberResponse.java diff --git a/server/src/main/java/server/haengdong/presentation/response/CurrentMemberResponse.java b/server/src/main/java/server/haengdong/presentation/response/CurrentMemberResponse.java deleted file mode 100644 index 4308c7d17..000000000 --- a/server/src/main/java/server/haengdong/presentation/response/CurrentMemberResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package server.haengdong.presentation.response; - -import server.haengdong.application.response.CurrentMemberAppResponse; - -public record CurrentMemberResponse(String name) { - - public static CurrentMemberResponse of(CurrentMemberAppResponse response) { - return new CurrentMemberResponse(response.name()); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java b/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java index 4eb915dd4..289cca4fa 100644 --- a/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java +++ b/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java @@ -3,11 +3,11 @@ import java.util.List; import server.haengdong.application.response.CurrentMemberAppResponse; -public record CurrentMembersResponse(List<CurrentMemberResponse> members) { +public record CurrentMembersResponse(List<String> memberNames) { public static CurrentMembersResponse of(List<CurrentMemberAppResponse> currentMembers) { - List<CurrentMemberResponse> responses = currentMembers.stream() - .map(CurrentMemberResponse::of) + List<String> responses = currentMembers.stream() + .map(CurrentMemberAppResponse::name) .toList(); return new CurrentMembersResponse(responses); diff --git a/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java index 3105eb2c4..afd766c8f 100644 --- a/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java @@ -88,8 +88,8 @@ void getCurrentMembers() throws Exception { .accept(MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) - .andExpect(jsonPath("$.members[0].name").value(equalTo("소하"))) - .andExpect(jsonPath("$.members[1].name").value(equalTo("토다리"))) + .andExpect(jsonPath("$.memberNames[0]").value(equalTo("소하"))) + .andExpect(jsonPath("$.memberNames[1]").value(equalTo("토다리"))) .andDo( document("getCurrentMembers", preprocessRequest(prettyPrint()), @@ -98,10 +98,8 @@ void getCurrentMembers() throws Exception { parameterWithName("eventId").description("행사 ID") ), responseFields( - fieldWithPath("members").type(JsonFieldType.ARRAY) - .description("액션 대상 참여자 목록"), - fieldWithPath("members[0].name").type(JsonFieldType.STRING) - .description("참여자 이름") + fieldWithPath("memberNames").type(JsonFieldType.ARRAY) + .description("현재 탈주 가능한 참여 인원 이름 목록") ) ) ); diff --git a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java index 1e8fa239f..f50c70a17 100644 --- a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java @@ -46,8 +46,8 @@ void getCurrentMembers() throws Exception { .accept(MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) - .andExpect(jsonPath("$.members[0].name").value(equalTo("소하"))) - .andExpect(jsonPath("$.members[1].name").value(equalTo("토다리"))); + .andExpect(jsonPath("$.memberNames[0]").value(equalTo("소하"))) + .andExpect(jsonPath("$.memberNames[1]").value(equalTo("토다리"))); } @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") From 92dd8ce76c7cab532b9431f085ffdce03295a40b Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Fri, 16 Aug 2024 13:59:30 +0900 Subject: [PATCH 143/178] =?UTF-8?q?feat:=20BillActionDetail=20=EB=B2=A0?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EC=BD=94=EB=93=9C=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?(#363)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/BillActionDetailService.java | 12 ++++++++ .../domain/action/BillActionDetail.java | 28 +++++++++++++++++++ .../action/BillActionDetailRepository.java | 8 ++++++ .../BillActionDetailController.java | 12 ++++++++ 4 files changed, 60 insertions(+) create mode 100644 server/src/main/java/server/haengdong/application/BillActionDetailService.java create mode 100644 server/src/main/java/server/haengdong/domain/action/BillActionDetail.java create mode 100644 server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java create mode 100644 server/src/main/java/server/haengdong/presentation/BillActionDetailController.java diff --git a/server/src/main/java/server/haengdong/application/BillActionDetailService.java b/server/src/main/java/server/haengdong/application/BillActionDetailService.java new file mode 100644 index 000000000..14a7e8a06 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/BillActionDetailService.java @@ -0,0 +1,12 @@ +package server.haengdong.application; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import server.haengdong.domain.action.BillActionRepository; + +@RequiredArgsConstructor +@Service +public class BillActionDetailService { + + private final BillActionRepository billActionRepository; +} diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java new file mode 100644 index 000000000..6cd01a667 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java @@ -0,0 +1,28 @@ +package server.haengdong.domain.action; + +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class BillActionDetail { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + private BillAction billAction; + + private String memberName; + + private Long price; +} diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java new file mode 100644 index 000000000..eb910eabf --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java @@ -0,0 +1,8 @@ +package server.haengdong.domain.action; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface BillActionDetailRepository extends JpaRepository<BillActionDetail, Long> { +} diff --git a/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java b/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java new file mode 100644 index 000000000..376b4ff26 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java @@ -0,0 +1,12 @@ +package server.haengdong.presentation; + +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.BillActionDetailService; + +@RequiredArgsConstructor +@RestController +public class BillActionDetailController { + + private final BillActionDetailService billActionDetailService; +} From 68be926b4e094fc71edb81c8e5085d225a00382f Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Fri, 16 Aug 2024 16:38:52 +0900 Subject: [PATCH 144/178] =?UTF-8?q?feat:=20=EC=95=A1=EC=85=98=20=EC=9D=B4?= =?UTF-8?q?=EB=A0=A5=20=EC=A1=B0=ED=9A=8C=20v2=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20(#375)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/EventController.java | 11 ++++ .../response/ActionResponse2.java | 22 +++++++ .../response/ActionsResponse.java | 14 +++++ .../docs/EventControllerDocsTest.java | 63 +++++++++++++++++++ 4 files changed, 110 insertions(+) create mode 100644 server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java index 54de966e5..34261042f 100644 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -1,6 +1,7 @@ package server.haengdong.presentation; import jakarta.validation.Valid; +import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -15,10 +16,12 @@ import org.springframework.web.bind.annotation.RestController; import server.haengdong.application.AuthService; import server.haengdong.application.EventService; +import server.haengdong.application.response.ActionAppResponse; import server.haengdong.infrastructure.auth.CookieProperties; import server.haengdong.presentation.request.EventLoginRequest; import server.haengdong.presentation.request.EventSaveRequest; import server.haengdong.presentation.request.MemberNamesUpdateRequest; +import server.haengdong.presentation.response.ActionsResponse; import server.haengdong.presentation.response.EventDetailResponse; import server.haengdong.presentation.response.EventResponse; import server.haengdong.presentation.response.MembersResponse; @@ -60,6 +63,14 @@ public ResponseEntity<StepsResponse> findActions(@PathVariable("eventId") String return ResponseEntity.ok(stepsResponse); } + @GetMapping("/api/events/{eventId}/actions/v2") + public ResponseEntity<ActionsResponse> findActions2(@PathVariable("eventId") String token) { + List<ActionAppResponse> actions = eventService.findActions(token); + ActionsResponse actionsResponse = ActionsResponse.of(actions); + + return ResponseEntity.ok(actionsResponse); + } + @GetMapping("/api/events/{eventId}/members") public ResponseEntity<MembersResponse> findAllMembers(@PathVariable("eventId") String token) { MembersResponse response = MembersResponse.of(eventService.findAllMembers(token)); diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java b/server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java new file mode 100644 index 000000000..ea46c5bd9 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java @@ -0,0 +1,22 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.ActionAppResponse; + +public record ActionResponse2( + Long actionId, + String name, + Long price, + Long sequence, + String type +) { + + public static ActionResponse2 of(ActionAppResponse actionAppResponse) { + return new ActionResponse2( + actionAppResponse.actionId(), + actionAppResponse.name(), + actionAppResponse.price(), + actionAppResponse.sequence(), + actionAppResponse.actionType().name() + ); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java b/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java new file mode 100644 index 000000000..88c0184ec --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java @@ -0,0 +1,14 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import server.haengdong.application.response.ActionAppResponse; + +public record ActionsResponse( + List<ActionResponse2> actions +) { + public static ActionsResponse of(List<ActionAppResponse> actions) { + return new ActionsResponse(actions.stream() + .map(ActionResponse2::of) + .toList()); + } +} diff --git a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java index 09546bcc3..39c023d45 100644 --- a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java @@ -284,6 +284,69 @@ void findActions() throws Exception { ); } + @DisplayName("행사 전체 액션 이력 조회 v2") + @Test + void findActions2() throws Exception { + String token = "TOKEN"; + List<ActionAppResponse> actionAppResponses = List.of( + new ActionAppResponse(1L, "망쵸", null, 1L, ActionType.IN), + new ActionAppResponse(2L, "족발", 100L, 2L, ActionType.BILL), + new ActionAppResponse(3L, "인생네컷", 1000L, 3L, ActionType.BILL), + new ActionAppResponse(4L, "망쵸", null, 4L, ActionType.OUT) + ); + given(eventService.findActions(token)).willReturn(actionAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/actions/v2", token) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.actions[0].actionId").value(equalTo(1))) + .andExpect(jsonPath("$.actions[0].name").value(equalTo("망쵸"))) + .andExpect(jsonPath("$.actions[0].price").value(equalTo(null))) + .andExpect(jsonPath("$.actions[0].sequence").value(equalTo(1))) + .andExpect(jsonPath("$.actions[0].type").value(equalTo("IN"))) + + .andExpect(jsonPath("$.actions[1].actionId").value(equalTo(2))) + .andExpect(jsonPath("$.actions[1].name").value(equalTo("족발"))) + .andExpect(jsonPath("$.actions[1].price").value(equalTo(100))) + .andExpect(jsonPath("$.actions[1].sequence").value(equalTo(2))) + .andExpect(jsonPath("$.actions[1].type").value(equalTo("BILL"))) + + .andExpect(jsonPath("$.actions[2].actionId").value(equalTo(3))) + .andExpect(jsonPath("$.actions[2].name").value(equalTo("인생네컷"))) + .andExpect(jsonPath("$.actions[2].price").value(equalTo(1000))) + .andExpect(jsonPath("$.actions[2].sequence").value(equalTo(3))) + .andExpect(jsonPath("$.actions[2].type").value(equalTo("BILL"))) + + .andExpect(jsonPath("$.actions[3].actionId").value(equalTo(4))) + .andExpect(jsonPath("$.actions[3].name").value(equalTo("망쵸"))) + .andExpect(jsonPath("$.actions[3].price").value(equalTo(null))) + .andExpect(jsonPath("$.actions[3].sequence").value(equalTo(4))) + .andExpect(jsonPath("$.actions[3].type").value(equalTo("OUT"))) + + .andDo( + document("findActions", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("actions[].actionId").type(JsonFieldType.NUMBER) + .description("액션 ID"), + fieldWithPath("actions[].name").type(JsonFieldType.STRING) + .description("참여자 액션일 경우 참여자 이름, 지출 액션일 경우 지출 내역 이름"), + fieldWithPath("actions[].price").type(JsonFieldType.NUMBER).optional() + .description("참여자 액션일 경우 null, 지출 액션일 경우 지출 금액"), + fieldWithPath("actions[].sequence").type(JsonFieldType.NUMBER) + .description("액션 순서"), + fieldWithPath("actions[].type").type(JsonFieldType.STRING) + .description("액션 타입") + ) + ) + ); + } + @DisplayName("행사 어드민 권한을 확인한다.") @Test void authenticateTest() throws Exception { From 45f147de0f963adca9edf59b82ceb7cc0e5ab26c Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Fri, 16 Aug 2024 17:47:13 +0900 Subject: [PATCH 145/178] =?UTF-8?q?[BE]=20=ED=96=89=EC=82=AC=20=EC=B0=B8?= =?UTF-8?q?=EC=97=AC=20=EC=9D=B8=EC=9B=90=20=EB=98=90=EB=8A=94=20=EC=A7=80?= =?UTF-8?q?=EC=B6=9C=20=EC=B4=9D=EC=95=A1=20=EB=B3=80=EB=8F=99=EC=8B=9C=20?= =?UTF-8?q?=EC=B0=A8=EB=93=B1=20=EC=A0=95=EC=82=B0=20=EC=B4=88=EA=B8=B0?= =?UTF-8?q?=ED=99=94=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20(#370)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 지출 액션 수정시 지출 디테일 초기화 기능 구현 * feat: 맴버 액션 삭제시 지출 디테일 초기화 기능 구현 * feat: 맴버 삭제시 지출 디테일 초기화 기능 구현 * fix: 버그 수정 * fix: 버그 수정 --- .../application/BillActionService.java | 16 ++++ .../application/MemberActionService.java | 30 ++++++- .../domain/action/BillActionDetail.java | 10 +++ .../action/BillActionDetailRepository.java | 5 ++ .../domain/action/BillActionRepository.java | 8 ++ .../domain/action/CurrentMembers.java | 4 + .../domain/action/MemberActionRepository.java | 7 ++ .../application/BillActionServiceTest.java | 38 ++++++++ .../application/MemberActionServiceTest.java | 87 +++++++++++++++++++ 9 files changed, 203 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java index 468508d07..de79f9f5f 100644 --- a/server/src/main/java/server/haengdong/application/BillActionService.java +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -9,6 +9,8 @@ import server.haengdong.domain.action.Action; import server.haengdong.domain.action.ActionRepository; import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; +import server.haengdong.domain.action.BillActionDetailRepository; import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; @@ -23,6 +25,7 @@ public class BillActionService { private final BillActionRepository billActionRepository; private final ActionRepository actionRepository; private final EventRepository eventRepository; + private final BillActionDetailRepository billActionDetailRepository; @Transactional public void saveAllBillAction(String eventToken, List<BillActionAppRequest> requests) { @@ -49,10 +52,23 @@ public void updateBillAction(String token, Long actionId, BillActionUpdateAppReq validateToken(token, billAction); + resetBillActionDetail(billAction, request.price()); + BillAction updatedBillAction = billAction.update(request.title(), request.price()); billActionRepository.save(updatedBillAction); } + private void resetBillActionDetail(BillAction billAction, Long updatePrice) { + if (billAction.getPrice() != updatePrice) { + List<BillActionDetail> billActionDetails = billActionDetailRepository.findByBillAction(billAction); + int memberCount = billActionDetails.size(); + if (memberCount != 0) { + Long eachPrice = updatePrice / memberCount; + billActionDetails.forEach(billActionDetail -> billActionDetail.updatePrice(eachPrice)); + } + } + } + private void validateToken(String token, BillAction billAction) { Event event = billAction.getEvent(); if (event.isTokenMismatch(token)) { diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java index 79318fa98..5b9416888 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionService.java +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -8,6 +8,10 @@ import server.haengdong.application.response.CurrentMemberAppResponse; import server.haengdong.domain.action.Action; import server.haengdong.domain.action.ActionRepository; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; +import server.haengdong.domain.action.BillActionDetailRepository; +import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.action.CurrentMembers; import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionRepository; @@ -25,6 +29,8 @@ public class MemberActionService { private final MemberActionRepository memberActionRepository; private final EventRepository eventRepository; private final ActionRepository actionRepository; + private final BillActionDetailRepository billActionDetailRepository; + private final BillActionRepository billActionRepository; @Transactional public void saveMemberAction(String token, MemberActionsSaveAppRequest request) { @@ -65,6 +71,9 @@ public void deleteMember(String token, String memberName) { .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); memberActionRepository.deleteAllByEventAndMemberName(event, memberName); + + List<BillAction> billActions = billActionRepository.findByAction_Event(event); + billActions.forEach(billAction -> resetBillAction(event, billAction)); } @Transactional @@ -76,7 +85,24 @@ public void deleteMemberAction(String token, Long actionId) { MemberAction memberAction = memberActionRepository.findByAction(action) .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_ACTION_NOT_FOUND)); - memberActionRepository.deleteAllByMemberNameAndMinSequence(memberAction.getMemberName(), - memberAction.getSequence()); + memberActionRepository.deleteAllByMemberNameAndMinSequence(memberAction.getMemberName(), memberAction.getSequence()); + + List<BillAction> billActions = billActionRepository.findByEventAndGreaterThanSequence(event, action.getSequence()); + billActions.forEach(billAction -> resetBillAction(event, billAction)); + } + + private void resetBillAction(Event event, BillAction billAction) { + List<MemberAction> memberActions = memberActionRepository.findByEventAndSequence(event, billAction.getSequence()); + CurrentMembers currentMembers = CurrentMembers.of(memberActions); + + billActionDetailRepository.deleteAllByBillAction(billAction); + + if (currentMembers.isNotEmpty()) { + Long eachPrice = billAction.getPrice() / currentMembers.size(); + for (String member : currentMembers.getMembers()) { + BillActionDetail billActionDetail = new BillActionDetail(billAction, member, eachPrice); + billActionDetailRepository.save(billActionDetail); + } + } } } diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java index 6cd01a667..161a6663b 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java @@ -25,4 +25,14 @@ public class BillActionDetail { private String memberName; private Long price; + + public BillActionDetail(BillAction billAction, String memberName, Long price) { + this.billAction = billAction; + this.memberName = memberName; + this.price = price; + } + + public void updatePrice(Long price) { + this.price = price; + } } diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java index eb910eabf..3bda6d020 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java @@ -1,8 +1,13 @@ package server.haengdong.domain.action; +import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface BillActionDetailRepository extends JpaRepository<BillActionDetail, Long> { + + List<BillActionDetail> findByBillAction(BillAction billAction); + + void deleteAllByBillAction(BillAction billAction); } diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java index a0e6a1bf1..817a63bf8 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java @@ -4,6 +4,7 @@ import java.util.Optional; import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import server.haengdong.domain.event.Event; @@ -16,4 +17,11 @@ public interface BillActionRepository extends JpaRepository<BillAction, Long> { void deleteByAction_EventAndActionId(Event event, Long actionId); Optional<BillAction> findByAction_Id(Long actionId); + + @Query(""" + select ba + from BillAction ba + where ba.action.event = :event and ba.action.sequence > :sequence + """) + List<BillAction> findByEventAndGreaterThanSequence(Event event, Long sequence); } diff --git a/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java b/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java index 7706c05d1..9a85c6075 100644 --- a/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java +++ b/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java @@ -67,6 +67,10 @@ public boolean isEmpty() { return members.isEmpty(); } + public boolean isNotEmpty() { + return !isEmpty(); + } + public int size() { return members.size(); } diff --git a/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java index 8cf9e42cf..324ff9797 100644 --- a/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java @@ -43,4 +43,11 @@ public interface MemberActionRepository extends JpaRepository<MemberAction, Long List<MemberAction> findAllByAction_EventAndMemberName(Event event, String memberName); boolean existsByAction_EventAndMemberName(Event event, String updatedMemberName); + + @Query(""" + select ma + from MemberAction ma + where ma.action.event = :event and ma.action.sequence < :sequence + """) + List<MemberAction> findByEventAndSequence(Event event, Long sequence); } diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java index 51eaa6e0b..f43fe8968 100644 --- a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java @@ -13,6 +13,8 @@ import server.haengdong.application.request.BillActionUpdateAppRequest; import server.haengdong.domain.action.Action; import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; +import server.haengdong.domain.action.BillActionDetailRepository; import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; @@ -30,6 +32,9 @@ class BillActionServiceTest extends ServiceTestSupport { @Autowired private BillActionRepository billActionRepository; + @Autowired + private BillActionDetailRepository billActionDetailRepository; + @DisplayName("지출 내역을 생성한다.") @Test void saveAllBillAction() { @@ -107,6 +112,39 @@ void updateBillAction1() { .isInstanceOf(HaengdongException.class); } + @DisplayName("지출 내역 금액을 변경하면 지출 디테일이 초기화 된다.") + @Test + void updateBillAction2() { + Event event = Fixture.EVENT1; + Event savedEvent = eventRepository.save(event); + Action action = Action.createFirst(savedEvent); + BillAction billAction = new BillAction(action, "뽕족", 10_000L); + BillAction savedBillAction = billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(savedBillAction, "감자", 3000L); + BillActionDetail billActionDetail2 = new BillActionDetail(savedBillAction, "고구마", 2000L); + BillActionDetail billActionDetail3 = new BillActionDetail(savedBillAction, "당근", 3000L); + BillActionDetail billActionDetail4 = new BillActionDetail(savedBillAction, "양파", 2000L); + + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3, billActionDetail4)); + + Long actionId = savedBillAction.getAction().getId(); + BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L); + + billActionService.updateBillAction(event.getToken(), actionId, request); + + BillAction updatedBillAction = billActionRepository.findById(savedBillAction.getId()).get(); + List<BillActionDetail> billActionDetails = billActionDetailRepository.findByBillAction(updatedBillAction); + + assertThat(billActionDetails).hasSize(4) + .extracting("memberName", "price") + .containsExactlyInAnyOrder( + tuple("감자", 5000L), + tuple("고구마", 5000L), + tuple("당근", 5000L), + tuple("양파", 5000L) + ); + } + @DisplayName("지출 내역을 삭제한다.") @Test void deleteBillAction() { diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java index 8f0af8dfe..14a7d4225 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java @@ -14,6 +14,10 @@ import server.haengdong.application.request.MemberActionSaveAppRequest; import server.haengdong.application.request.MemberActionsSaveAppRequest; import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; +import server.haengdong.domain.action.BillActionDetailRepository; +import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionRepository; import server.haengdong.domain.action.MemberActionStatus; @@ -33,6 +37,12 @@ class MemberActionServiceTest extends ServiceTestSupport { @Autowired private EventRepository eventRepository; + @Autowired + private BillActionRepository billActionRepository; + + @Autowired + private BillActionDetailRepository billActionDetailRepository; + @DisplayName("현재 행사에 참여하고 있는 경우에 나갈 수 있다.") @Test void saveMemberActionTest() { @@ -115,6 +125,44 @@ void deleteMember() { ); } + @DisplayName("이벤트에 속한 멤버을 삭제하면 전체 지출 내역 디테일이 초기화된다.") + @Test + void deleteMember1() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + MemberAction memberAction1 = createMemberAction(new Action(event, 1L), "토다리", IN, 1L); + Action targetAction = new Action(event, 2L); + MemberAction memberAction2 = createMemberAction(targetAction, "토다리", OUT, 2L); + MemberAction memberAction3 = createMemberAction(new Action(event, 3L), "쿠키", IN, 3L); + MemberAction memberAction4 = createMemberAction(new Action(event, 4L), "웨디", IN, 4L); + MemberAction memberAction5 = createMemberAction(new Action(event, 5L), "감자", IN, 5L); + memberActionRepository.saveAll( + List.of(memberAction1, + memberAction2, + memberAction3, + memberAction4, + memberAction5 + ) + ); + BillAction billAction = new BillAction(new Action(event, 6L), "뽕족", 100_000L); + billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "쿠키", 40_000L); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "웨디", 30_000L); + BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "감자", 30_000L); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3)); + + memberActionService.deleteMember(event.getToken(), "쿠키"); + + List<BillActionDetail> billActionDetails = billActionDetailRepository.findByBillAction(billAction); + + assertThat(billActionDetails).hasSize(2) + .extracting("memberName", "price") + .containsExactlyInAnyOrder( + tuple("웨디", 50_000L), + tuple("감자", 50_000L) + ); + } + @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") @Test void deleteMemberAction() { @@ -151,6 +199,45 @@ void deleteMemberAction() { ); } + @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후 지출 내역 디테일이 초기화된다.") + @Test + void deleteMemberAction1() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + MemberAction memberAction1 = createMemberAction(new Action(event, 1L), "토다리", IN, 1L); + Action targetAction = new Action(event, 2L); + MemberAction memberAction2 = createMemberAction(targetAction, "토다리", OUT, 2L); + MemberAction memberAction3 = createMemberAction(new Action(event, 3L), "쿠키", IN, 3L); + MemberAction memberAction4 = createMemberAction(new Action(event, 4L), "웨디", IN, 4L); + MemberAction memberAction5 = createMemberAction(new Action(event, 5L), "감자", IN, 5L); + memberActionRepository.saveAll( + List.of(memberAction1, + memberAction2, + memberAction3, + memberAction4, + memberAction5 + ) + ); + BillAction billAction = new BillAction(new Action(event, 6L), "뽕족", 100_000L); + billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "쿠키", 40_000L); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "웨디", 30_000L); + BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "감자", 30_000L); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3)); + + memberActionService.deleteMemberAction(event.getToken(), targetAction.getId()); + List<BillActionDetail> billActionDetails = billActionDetailRepository.findByBillAction(billAction); + + assertThat(billActionDetails).hasSize(4) + .extracting("memberName", "price") + .containsExactlyInAnyOrder( + tuple("토다리", 25_000L), + tuple("쿠키", 25_000L), + tuple("웨디", 25_000L), + tuple("감자", 25_000L) + ); + } + private MemberAction createMemberAction( Action action, String memberName, From 55fb09414e4b7f95b097a98d09ac8f0b0def958d Mon Sep 17 00:00:00 2001 From: Juhwan Kim <13selfesteem91@naver.com> Date: Mon, 19 Aug 2024 14:06:12 +0900 Subject: [PATCH 146/178] =?UTF-8?q?feat:=20=EC=9A=94=EA=B5=AC=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EB=B3=80=EA=B2=BD=EC=97=90=20=EB=94=B0=EB=A5=B8=20?= =?UTF-8?q?=EC=A7=80=EC=B6=9C=20=EB=82=B4=EC=97=AD=20=EC=B6=94=EA=B0=80,?= =?UTF-8?q?=20=EC=A7=80=EC=B6=9C=20=EC=95=A1=EC=85=98=20=EC=82=AD=EC=A0=9C?= =?UTF-8?q?=20API=20=EC=88=98=EC=A0=95=20(#373)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 지출 내역 추가 시, 상세 내역 생성 로직 추가 * feat: 지출 내역 삭제 시, 상세 내역 삭제 로직 추가 * fix: 멤버가 없는 상황에 대해 0으로 나누는 상황 방지 --- .../application/BillActionService.java | 19 ++- .../application/MemberActionService.java | 9 +- .../action/BillActionDetailRepository.java | 3 + .../domain/action/CurrentMembers.java | 2 +- .../response/ActionsResponse.java | 4 +- .../application/BillActionServiceTest.java | 69 +++++++- .../docs/EventControllerDocsTest.java | 156 +++++++++--------- 7 files changed, 175 insertions(+), 87 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java index de79f9f5f..078752191 100644 --- a/server/src/main/java/server/haengdong/application/BillActionService.java +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -12,6 +12,9 @@ import server.haengdong.domain.action.BillActionDetail; import server.haengdong.domain.action.BillActionDetailRepository; import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.CurrentMembers; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.exception.HaengdongErrorCode; @@ -23,19 +26,25 @@ public class BillActionService { private final BillActionRepository billActionRepository; + private final BillActionDetailRepository billActionDetailRepository; + private final MemberActionRepository memberActionRepository; private final ActionRepository actionRepository; private final EventRepository eventRepository; - private final BillActionDetailRepository billActionDetailRepository; @Transactional public void saveAllBillAction(String eventToken, List<BillActionAppRequest> requests) { Event event = getEvent(eventToken); Action action = createStartAction(event); + List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event); + CurrentMembers currentMembers = CurrentMembers.of(findMemberActions); for (BillActionAppRequest request : requests) { BillAction billAction = request.toBillAction(action); billActionRepository.save(billAction); action = action.next(); + if (currentMembers.isNotEmpty()) { + saveBillActionDetails(billAction, currentMembers); + } } } @@ -45,6 +54,13 @@ private Action createStartAction(Event event) { .orElse(Action.createFirst(event)); } + private void saveBillActionDetails(BillAction billAction, CurrentMembers currentMembers) { + long pricePerMember = billAction.getPrice() / currentMembers.size(); + currentMembers.getMembers().stream() + .map(memberName -> new BillActionDetail(billAction, memberName, pricePerMember)) + .forEach(billActionDetailRepository::save); + } + @Transactional public void updateBillAction(String token, Long actionId, BillActionUpdateAppRequest request) { BillAction billAction = billActionRepository.findByAction_Id(actionId) @@ -86,6 +102,7 @@ public void deleteBillAction(String token, Long actionId) { Event event = eventRepository.findByToken(token) .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + billActionDetailRepository.deleteByBillAction_Action_EventAndBillAction_ActionId(event, actionId); billActionRepository.deleteByAction_EventAndActionId(event, actionId); } } diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java index 5b9416888..47d336c60 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionService.java +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -85,14 +85,17 @@ public void deleteMemberAction(String token, Long actionId) { MemberAction memberAction = memberActionRepository.findByAction(action) .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_ACTION_NOT_FOUND)); - memberActionRepository.deleteAllByMemberNameAndMinSequence(memberAction.getMemberName(), memberAction.getSequence()); + memberActionRepository.deleteAllByMemberNameAndMinSequence(memberAction.getMemberName(), + memberAction.getSequence()); - List<BillAction> billActions = billActionRepository.findByEventAndGreaterThanSequence(event, action.getSequence()); + List<BillAction> billActions = billActionRepository.findByEventAndGreaterThanSequence(event, + action.getSequence()); billActions.forEach(billAction -> resetBillAction(event, billAction)); } private void resetBillAction(Event event, BillAction billAction) { - List<MemberAction> memberActions = memberActionRepository.findByEventAndSequence(event, billAction.getSequence()); + List<MemberAction> memberActions = memberActionRepository.findByEventAndSequence(event, + billAction.getSequence()); CurrentMembers currentMembers = CurrentMembers.of(memberActions); billActionDetailRepository.deleteAllByBillAction(billAction); diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java index 3bda6d020..5d74462ff 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java @@ -3,6 +3,7 @@ import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import server.haengdong.domain.event.Event; @Repository public interface BillActionDetailRepository extends JpaRepository<BillActionDetail, Long> { @@ -10,4 +11,6 @@ public interface BillActionDetailRepository extends JpaRepository<BillActionDeta List<BillActionDetail> findByBillAction(BillAction billAction); void deleteAllByBillAction(BillAction billAction); + + void deleteByBillAction_Action_EventAndBillAction_ActionId(Event event, Long actionId); } diff --git a/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java b/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java index 9a85c6075..ba380aae5 100644 --- a/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java +++ b/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java @@ -68,7 +68,7 @@ public boolean isEmpty() { } public boolean isNotEmpty() { - return !isEmpty(); + return !members.isEmpty(); } public int size() { diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java b/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java index 88c0184ec..c8ae780e3 100644 --- a/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java +++ b/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java @@ -8,7 +8,7 @@ public record ActionsResponse( ) { public static ActionsResponse of(List<ActionAppResponse> actions) { return new ActionsResponse(actions.stream() - .map(ActionResponse2::of) - .toList()); + .map(ActionResponse2::of) + .toList()); } } diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java index f43fe8968..fc0db9a37 100644 --- a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java @@ -16,6 +16,9 @@ import server.haengdong.domain.action.BillActionDetail; import server.haengdong.domain.action.BillActionDetailRepository; import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.action.MemberActionStatus; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.exception.HaengdongException; @@ -35,11 +38,19 @@ class BillActionServiceTest extends ServiceTestSupport { @Autowired private BillActionDetailRepository billActionDetailRepository; + @Autowired + private MemberActionRepository memberActionRepository; + @DisplayName("지출 내역을 생성한다.") @Test void saveAllBillAction() { Event event = Fixture.EVENT1; Event savedEvent = eventRepository.save(event); + Action action1 = new Action(event, 1L); + Action action2 = new Action(event, 2L); + MemberAction memberAction1 = new MemberAction(action1, "백호", MemberActionStatus.IN, 1L); + MemberAction memberAction2 = new MemberAction(action2, "망쵸", MemberActionStatus.IN, 2L); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); List<BillActionAppRequest> requests = List.of( new BillActionAppRequest("뽕족", 10_000L), @@ -52,8 +63,39 @@ void saveAllBillAction() { assertThat(actions).extracting(BillAction::getTitle, BillAction::getPrice, BillAction::getSequence) .containsExactlyInAnyOrder( - tuple("뽕족", 10_000L, 1L), - tuple("인생맥주", 15_000L, 2L) + tuple("뽕족", 10_000L, 3L), + tuple("인생맥주", 15_000L, 4L) + ); + } + + @DisplayName("지출 내역을 생성하면 지출 상세 내역이 생성된다.") + @Test + void saveAllBillActionTest1() { + Event event = Fixture.EVENT1; + Event savedEvent = eventRepository.save(event); + Action action1 = new Action(event, 1L); + Action action2 = new Action(event, 2L); + MemberAction memberAction1 = new MemberAction(action1, "백호", MemberActionStatus.IN, 1L); + MemberAction memberAction2 = new MemberAction(action2, "망쵸", MemberActionStatus.IN, 2L); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); + + List<BillActionAppRequest> request = List.of( + new BillActionAppRequest("뽕족", 10_000L), + new BillActionAppRequest("인생맥주", 15_000L) + ); + + billActionService.saveAllBillAction(event.getToken(), request); + + List<BillActionDetail> billActionDetails = billActionDetailRepository.findAll(); + + assertThat(billActionDetails) + .hasSize(4) + .extracting("memberName", "price") + .containsExactlyInAnyOrder( + tuple("백호", 5_000L), + tuple("망쵸", 5_000L), + tuple("백호", 7_500L), + tuple("망쵸", 7_500L) ); } @@ -125,7 +167,8 @@ void updateBillAction2() { BillActionDetail billActionDetail3 = new BillActionDetail(savedBillAction, "당근", 3000L); BillActionDetail billActionDetail4 = new BillActionDetail(savedBillAction, "양파", 2000L); - billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3, billActionDetail4)); + billActionDetailRepository.saveAll( + List.of(billActionDetail1, billActionDetail2, billActionDetail3, billActionDetail4)); Long actionId = savedBillAction.getAction().getId(); BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L); @@ -159,6 +202,26 @@ void deleteBillAction() { assertThat(billActionRepository.findById(billAction.getId())).isEmpty(); } + @DisplayName("지출 내역을 삭제하면 지출 상세도 삭제된다.") + @Test + void deleteBillActionTest1() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "백호", MemberActionStatus.IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "망쵸", MemberActionStatus.IN, 2L); + BillAction billAction = new BillAction(new Action(event, 3L), "커피", 50_900L); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "백호", 25_450L); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "망쵸", 25_450L); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); + billActionRepository.save(billAction); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); + Long actionId = billAction.getAction().getId(); + + billActionService.deleteBillAction(event.getToken(), actionId); + + assertThat(billActionDetailRepository.findAll()).isEmpty(); + } + @DisplayName("지출 내역 삭제 시 행사가 존재하지 않으면 예외가 발생한다.") @Test void deleteBillAction1() { diff --git a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java index 39c023d45..9ee8985a3 100644 --- a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java @@ -136,15 +136,15 @@ void findAllMembersTest() throws Exception { .andExpect(jsonPath("$.memberNames[1]").value("쿠키")) .andDo( document("findAllEventMember", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - responseFields( - fieldWithPath("memberNames").type(JsonFieldType.ARRAY) - .description("행사 참여자 목록") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("memberNames").type(JsonFieldType.ARRAY) + .description("행사 참여자 목록") + ) ) ); } @@ -161,26 +161,28 @@ void updateMember() throws Exception { String requestBody = objectMapper.writeValueAsString(memberNameUpdateRequest); mockMvc.perform(put("/api/events/{eventId}/members/nameChange", token) - .cookie(EVENT_COOKIE) - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + .cookie(EVENT_COOKIE) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) .andDo(print()) .andExpect(status().isOk()) .andDo( document("updateEventMemberName", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") - ), - requestFields( - fieldWithPath("members").type(JsonFieldType.ARRAY).description("수정할 참여자 목록"), - fieldWithPath("members[].before").type(JsonFieldType.STRING).description("수정 전 참여자 이름"), - fieldWithPath("members[].after").type(JsonFieldType.STRING).description("수정 후 참여자 이름") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), + requestFields( + fieldWithPath("members").type(JsonFieldType.ARRAY).description("수정할 참여자 목록"), + fieldWithPath("members[].before").type(JsonFieldType.STRING) + .description("수정 전 참여자 이름"), + fieldWithPath("members[].after").type(JsonFieldType.STRING) + .description("수정 후 참여자 이름") + ) ) ); } @@ -195,25 +197,25 @@ void loginEvent() throws Exception { given(authService.getTokenName()).willReturn("eventToken"); mockMvc.perform(post("/api/events/{eventId}/login", token) - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) .andDo(print()) .andExpect(cookie().value("eventToken", "jwtToken")) .andExpect(status().isOk()) .andDo( document("eventLogin", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - requestFields( - fieldWithPath("password").type(JsonFieldType.STRING) - .description("행사 비밀 번호") - ), - responseCookies( - cookieWithName("eventToken").description("행사 관리자용 토큰") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestFields( + fieldWithPath("password").type(JsonFieldType.STRING) + .description("행사 비밀 번호") + ), + responseCookies( + cookieWithName("eventToken").description("행사 관리자용 토큰") + ) ) ); } @@ -231,7 +233,7 @@ void findActions() throws Exception { given(eventService.findActions(token)).willReturn(actionAppResponses); mockMvc.perform(get("/api/events/{eventId}/actions", token) - .accept(MediaType.APPLICATION_JSON)) + .accept(MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) .andExpect(jsonPath("$.steps[0].type").value(equalTo("IN"))) @@ -261,25 +263,25 @@ void findActions() throws Exception { .andDo( document("findActions", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - responseFields( - fieldWithPath("steps[].type").type(JsonFieldType.STRING) - .description("액션 유형 [BILL, IN, OUT]"), - fieldWithPath("steps[].members").type(JsonFieldType.ARRAY) - .description("해당 step에 참여한 참여자 목록"), - fieldWithPath("steps[].actions[].actionId").type(JsonFieldType.NUMBER) - .description("액션 ID"), - fieldWithPath("steps[].actions[].name").type(JsonFieldType.STRING) - .description("참여자 액션일 경우 참여자 이름, 지출 액션일 경우 지출 내역 이름"), - fieldWithPath("steps[].actions[].price").type(JsonFieldType.NUMBER).optional() - .description("참여자 액션일 경우 null, 지출 액션일 경우 지출 금액"), - fieldWithPath("steps[].actions[].sequence").type(JsonFieldType.NUMBER) - .description("액션 순서") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("steps[].type").type(JsonFieldType.STRING) + .description("액션 유형 [BILL, IN, OUT]"), + fieldWithPath("steps[].members").type(JsonFieldType.ARRAY) + .description("해당 step에 참여한 참여자 목록"), + fieldWithPath("steps[].actions[].actionId").type(JsonFieldType.NUMBER) + .description("액션 ID"), + fieldWithPath("steps[].actions[].name").type(JsonFieldType.STRING) + .description("참여자 액션일 경우 참여자 이름, 지출 액션일 경우 지출 내역 이름"), + fieldWithPath("steps[].actions[].price").type(JsonFieldType.NUMBER).optional() + .description("참여자 액션일 경우 null, 지출 액션일 경우 지출 금액"), + fieldWithPath("steps[].actions[].sequence").type(JsonFieldType.NUMBER) + .description("액션 순서") + ) ) ); } @@ -297,7 +299,7 @@ void findActions2() throws Exception { given(eventService.findActions(token)).willReturn(actionAppResponses); mockMvc.perform(get("/api/events/{eventId}/actions/v2", token) - .accept(MediaType.APPLICATION_JSON)) + .accept(MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) .andExpect(jsonPath("$.actions[0].actionId").value(equalTo(1))) @@ -326,23 +328,23 @@ void findActions2() throws Exception { .andDo( document("findActions", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - responseFields( - fieldWithPath("actions[].actionId").type(JsonFieldType.NUMBER) - .description("액션 ID"), - fieldWithPath("actions[].name").type(JsonFieldType.STRING) - .description("참여자 액션일 경우 참여자 이름, 지출 액션일 경우 지출 내역 이름"), - fieldWithPath("actions[].price").type(JsonFieldType.NUMBER).optional() - .description("참여자 액션일 경우 null, 지출 액션일 경우 지출 금액"), - fieldWithPath("actions[].sequence").type(JsonFieldType.NUMBER) - .description("액션 순서"), - fieldWithPath("actions[].type").type(JsonFieldType.STRING) - .description("액션 타입") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("actions[].actionId").type(JsonFieldType.NUMBER) + .description("액션 ID"), + fieldWithPath("actions[].name").type(JsonFieldType.STRING) + .description("참여자 액션일 경우 참여자 이름, 지출 액션일 경우 지출 내역 이름"), + fieldWithPath("actions[].price").type(JsonFieldType.NUMBER).optional() + .description("참여자 액션일 경우 null, 지출 액션일 경우 지출 금액"), + fieldWithPath("actions[].sequence").type(JsonFieldType.NUMBER) + .description("액션 순서"), + fieldWithPath("actions[].type").type(JsonFieldType.STRING) + .description("액션 타입") + ) ) ); } From 64d9ac8593eaac5f59b38dd9e569086055ddd7a2 Mon Sep 17 00:00:00 2001 From: JUHA <84626225+khabh@users.noreply.github.com> Date: Mon, 19 Aug 2024 14:26:41 +0900 Subject: [PATCH 147/178] =?UTF-8?q?refactor:=20=EC=B0=B8=EC=97=AC=EC=9E=90?= =?UTF-8?q?=EB=B3=84=20=EC=A0=95=EC=82=B0=20=ED=98=84=ED=99=A9=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EB=B0=8F=20=EC=95=A1=EC=85=98=20=EC=9D=B4=EB=A0=A5?= =?UTF-8?q?=20=EC=A1=B0=ED=9A=8C=20=EC=88=98=EC=A0=95=20(#377)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: BillActionDetail 변경 사항을 반영하여 참여자별 정산 현황 조회하도록 수정 * refactor: 액션 이력 조회 시 지출 액션 고정 금액 설정 여부 필드 추가 * refactor: isFixed 필드 삭제 * refactor: 메서드 이름 변경 * fix: BillAction 변경 로직 수정 --- .../haengdong/application/ActionService.java | 2 + .../application/BillActionService.java | 3 +- .../response/ActionAppResponse.java | 11 +- .../haengdong/domain/action/BillAction.java | 38 ++- .../domain/action/BillActionDetail.java | 13 + .../domain/action/MemberBillReport.java | 4 +- .../presentation/response/ActionResponse.java | 10 +- .../application/ActionServiceTest.java | 21 +- .../application/BillActionServiceTest.java | 12 +- .../docs/EventControllerDocsTest.java | 224 +++++++++--------- .../domain/action/BillActionTest.java | 37 ++- .../domain/action/MemberBillReportTest.java | 20 +- 12 files changed, 255 insertions(+), 140 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/ActionService.java b/server/src/main/java/server/haengdong/application/ActionService.java index 824b5afb9..bcf5e8b55 100644 --- a/server/src/main/java/server/haengdong/application/ActionService.java +++ b/server/src/main/java/server/haengdong/application/ActionService.java @@ -3,6 +3,7 @@ import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import server.haengdong.application.response.MemberBillReportAppResponse; import server.haengdong.domain.action.BillAction; import server.haengdong.domain.action.BillActionRepository; @@ -15,6 +16,7 @@ import server.haengdong.exception.HaengdongException; @RequiredArgsConstructor +@Transactional(readOnly = true) @Service public class ActionService { diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java index 078752191..803a21055 100644 --- a/server/src/main/java/server/haengdong/application/BillActionService.java +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -70,8 +70,7 @@ public void updateBillAction(String token, Long actionId, BillActionUpdateAppReq resetBillActionDetail(billAction, request.price()); - BillAction updatedBillAction = billAction.update(request.title(), request.price()); - billActionRepository.save(updatedBillAction); + billAction.update(request.title(), request.price()); } private void resetBillActionDetail(BillAction billAction, Long updatePrice) { diff --git a/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java b/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java index a1abcc35b..0c2c12611 100644 --- a/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java +++ b/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java @@ -9,16 +9,22 @@ public record ActionAppResponse( String name, Long price, Long sequence, + boolean isFixed, ActionType actionType ) { + public ActionAppResponse(Long actionId, String name, Long price, Long sequence, ActionType actionType) { + this(actionId, name, price, sequence, false, actionType); + } + public static ActionAppResponse of(BillAction billAction) { return new ActionAppResponse( billAction.getAction().getId(), billAction.getTitle(), billAction.getPrice(), billAction.getSequence(), - ActionType.BILL + billAction.isFixed(), + ActionAppResponse.ActionType.BILL ); } @@ -30,7 +36,8 @@ public static ActionAppResponse of(MemberAction memberAction) { memberAction.getMemberName(), null, memberAction.getSequence(), - ActionType.of(status) + false, + ActionAppResponse.ActionType.of(status) ); } diff --git a/server/src/main/java/server/haengdong/domain/action/BillAction.java b/server/src/main/java/server/haengdong/domain/action/BillAction.java index 1a50db47d..65db11734 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillAction.java +++ b/server/src/main/java/server/haengdong/domain/action/BillAction.java @@ -7,7 +7,10 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; import jakarta.persistence.OneToOne; +import java.util.ArrayList; +import java.util.List; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -24,6 +27,7 @@ public class BillAction implements Comparable<BillAction> { public static final int MAX_TITLE_LENGTH = 30; public static final long MIN_PRICE = 1L; public static final long MAX_PRICE = 10_000_000L; + private static final long DEFAULT_PRICE = 0L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -37,6 +41,9 @@ public class BillAction implements Comparable<BillAction> { private Long price; + @OneToMany(mappedBy = "billAction", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) + private List<BillActionDetail> billActionDetails = new ArrayList<>(); + public BillAction(Action action, String title, Long price) { this(null, action, title, price); } @@ -63,8 +70,11 @@ private void validatePrice(Long price) { } } - public BillAction update(String title, Long price) { - return new BillAction(id, action, title, price); + public void update(String title, Long price) { + validateTitle(title); + validatePrice(price); + this.title = title; + this.price = price; } public Long getSequence() { @@ -75,6 +85,30 @@ public Event getEvent() { return action.getEvent(); } + public Long findPriceByMemberName(String memberName) { + return billActionDetails.stream() + .filter(billActionDetail -> billActionDetail.hasMemberName(memberName)) + .map(BillActionDetail::getPrice) + .findFirst() + .orElse(DEFAULT_PRICE); + } + + public boolean isFixed() { + return billActionDetails.stream() + .map(BillActionDetail::getPrice) + .distinct() + .count() != 1L; + } + + public void addDetails(List<BillActionDetail> billActionDetails) { + billActionDetails.forEach(this::addDetail); + } + + private void addDetail(BillActionDetail billActionDetail) { + this.billActionDetails.add(billActionDetail); + billActionDetail.setBillAction(this); + } + @Override public int compareTo(BillAction o) { return Long.compare(this.getSequence(), o.getSequence()); diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java index 161a6663b..550499aa5 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java @@ -26,6 +26,19 @@ public class BillActionDetail { private Long price; + public BillActionDetail(String memberName, Long price) { + this.memberName = memberName; + this.price = price; + } + + public void setBillAction(BillAction billAction) { + this.billAction = billAction; + } + + public boolean hasMemberName(String memberName) { + return this.memberName.equals(memberName); + } + public BillActionDetail(BillAction billAction, String memberName, Long price) { this.billAction = billAction; this.memberName = memberName; diff --git a/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java b/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java index dbf2b49ac..7a707b9d8 100644 --- a/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java +++ b/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java @@ -66,9 +66,9 @@ private static void addBillAction( return; } - Long pricePerMember = billAction.getPrice() / currentMembers.size(); for (String currentMember : currentMembers.getMembers()) { - Long price = memberBillReports.get(currentMember) + pricePerMember; + Long currentPrice = billAction.findPriceByMemberName(currentMember); + Long price = memberBillReports.get(currentMember) + currentPrice; memberBillReports.put(currentMember, price); } } diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java b/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java index a58e60186..ea26ea769 100644 --- a/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java +++ b/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java @@ -6,15 +6,21 @@ public record ActionResponse( Long actionId, String name, Long price, - Long sequence + Long sequence, + boolean isFixed ) { + + public ActionResponse(Long actionId, String name, Long price, Long sequence) { + this(actionId, name, price, sequence, false); + } public static ActionResponse of(ActionAppResponse actionAppResponse) { return new ActionResponse( actionAppResponse.actionId(), actionAppResponse.name(), actionAppResponse.price(), - actionAppResponse.sequence() + actionAppResponse.sequence(), + actionAppResponse.isFixed() ); } } diff --git a/server/src/test/java/server/haengdong/application/ActionServiceTest.java b/server/src/test/java/server/haengdong/application/ActionServiceTest.java index 05a622d34..389b426df 100644 --- a/server/src/test/java/server/haengdong/application/ActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/ActionServiceTest.java @@ -13,6 +13,7 @@ import server.haengdong.application.response.MemberBillReportAppResponse; import server.haengdong.domain.action.Action; import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionRepository; @@ -49,9 +50,21 @@ void getMemberBillReports() { ); List<BillAction> billActions = List.of( new BillAction(new Action(savedEvent, 4L), "뽕족", 60_000L), - new BillAction(new Action(savedEvent, 6L), "인생맥주", 40_000L), new BillAction(new Action(savedEvent, 7L), "인생네컷", 20_000L) ); + billActions.get(0).addDetails( + List.of( + new BillActionDetail("소하", 10_000L), + new BillActionDetail("감자", 40_000L), + new BillActionDetail("쿠키", 10_000L) + ) + ); + billActions.get(1).addDetails( + List.of( + new BillActionDetail("소하", 5_000L), + new BillActionDetail("쿠키", 15_000L) + ) + ); memberActionRepository.saveAll(memberActions); billActionRepository.saveAll(billActions); @@ -61,9 +74,9 @@ void getMemberBillReports() { .hasSize(3) .extracting(MemberBillReportAppResponse::name, MemberBillReportAppResponse::price) .containsExactlyInAnyOrder( - tuple("감자", 20_000L), - tuple("쿠키", 50_000L), - tuple("소하", 50_000L) + tuple("감자", 40_000L), + tuple("쿠키", 25_000L), + tuple("소하", 15_000L) ); } diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java index fc0db9a37..be535411d 100644 --- a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java @@ -161,14 +161,12 @@ void updateBillAction2() { Event savedEvent = eventRepository.save(event); Action action = Action.createFirst(savedEvent); BillAction billAction = new BillAction(action, "뽕족", 10_000L); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "감자", 3000L); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "고구마", 2000L); + BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "당근", 3000L); + BillActionDetail billActionDetail4 = new BillActionDetail(billAction, "양파", 2000L); + billAction.addDetails(List.of(billActionDetail1, billActionDetail2, billActionDetail3, billActionDetail4)); BillAction savedBillAction = billActionRepository.save(billAction); - BillActionDetail billActionDetail1 = new BillActionDetail(savedBillAction, "감자", 3000L); - BillActionDetail billActionDetail2 = new BillActionDetail(savedBillAction, "고구마", 2000L); - BillActionDetail billActionDetail3 = new BillActionDetail(savedBillAction, "당근", 3000L); - BillActionDetail billActionDetail4 = new BillActionDetail(savedBillAction, "양파", 2000L); - - billActionDetailRepository.saveAll( - List.of(billActionDetail1, billActionDetail2, billActionDetail3, billActionDetail4)); Long actionId = savedBillAction.getAction().getId(); BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L); diff --git a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java index 9ee8985a3..bc7f15d6e 100644 --- a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java @@ -72,27 +72,27 @@ void saveEvent() throws Exception { given(authService.getTokenName()).willReturn("eventToken"); mockMvc.perform(post("/api/events") - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) .andDo(print()) .andExpect(status().isOk()) .andExpect(cookie().value("eventToken", "jwtToken")) .andExpect(jsonPath("$.eventId").value("쿠키 토큰")) .andDo( document("createEvent", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - requestFields( - fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름"), - fieldWithPath("password").type(JsonFieldType.STRING).description("행사 비밀 번호") - ), - responseFields( - fieldWithPath("eventId").type(JsonFieldType.STRING) - .description("행사 ID") - ), - responseCookies( - cookieWithName("eventToken").description("행사 관리자용 토큰") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + requestFields( + fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름"), + fieldWithPath("password").type(JsonFieldType.STRING).description("행사 비밀 번호") + ), + responseFields( + fieldWithPath("eventId").type(JsonFieldType.STRING) + .description("행사 ID") + ), + responseCookies( + cookieWithName("eventToken").description("행사 관리자용 토큰") + ) ) ); } @@ -110,14 +110,14 @@ void findEventTest() throws Exception { .andExpect(jsonPath("$.eventName").value("행동대장 회식")) .andDo( document("getEvent", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - responseFields( - fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름") + ) ) ); } @@ -136,15 +136,15 @@ void findAllMembersTest() throws Exception { .andExpect(jsonPath("$.memberNames[1]").value("쿠키")) .andDo( document("findAllEventMember", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - responseFields( - fieldWithPath("memberNames").type(JsonFieldType.ARRAY) - .description("행사 참여자 목록") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("memberNames").type(JsonFieldType.ARRAY) + .description("행사 참여자 목록") + ) ) ); } @@ -161,28 +161,28 @@ void updateMember() throws Exception { String requestBody = objectMapper.writeValueAsString(memberNameUpdateRequest); mockMvc.perform(put("/api/events/{eventId}/members/nameChange", token) - .cookie(EVENT_COOKIE) - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + .cookie(EVENT_COOKIE) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) .andDo(print()) .andExpect(status().isOk()) .andDo( document("updateEventMemberName", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") - ), - requestFields( - fieldWithPath("members").type(JsonFieldType.ARRAY).description("수정할 참여자 목록"), - fieldWithPath("members[].before").type(JsonFieldType.STRING) - .description("수정 전 참여자 이름"), - fieldWithPath("members[].after").type(JsonFieldType.STRING) - .description("수정 후 참여자 이름") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), + requestFields( + fieldWithPath("members").type(JsonFieldType.ARRAY).description("수정할 참여자 목록"), + fieldWithPath("members[].before").type(JsonFieldType.STRING) + .description("수정 전 참여자 이름"), + fieldWithPath("members[].after").type(JsonFieldType.STRING) + .description("수정 후 참여자 이름") + ) ) ); } @@ -197,25 +197,25 @@ void loginEvent() throws Exception { given(authService.getTokenName()).willReturn("eventToken"); mockMvc.perform(post("/api/events/{eventId}/login", token) - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) .andDo(print()) .andExpect(cookie().value("eventToken", "jwtToken")) .andExpect(status().isOk()) .andDo( document("eventLogin", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - requestFields( - fieldWithPath("password").type(JsonFieldType.STRING) - .description("행사 비밀 번호") - ), - responseCookies( - cookieWithName("eventToken").description("행사 관리자용 토큰") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestFields( + fieldWithPath("password").type(JsonFieldType.STRING) + .description("행사 비밀 번호") + ), + responseCookies( + cookieWithName("eventToken").description("행사 관리자용 토큰") + ) ) ); } @@ -233,7 +233,7 @@ void findActions() throws Exception { given(eventService.findActions(token)).willReturn(actionAppResponses); mockMvc.perform(get("/api/events/{eventId}/actions", token) - .accept(MediaType.APPLICATION_JSON)) + .accept(MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) .andExpect(jsonPath("$.steps[0].type").value(equalTo("IN"))) @@ -263,25 +263,27 @@ void findActions() throws Exception { .andDo( document("findActions", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - responseFields( - fieldWithPath("steps[].type").type(JsonFieldType.STRING) - .description("액션 유형 [BILL, IN, OUT]"), - fieldWithPath("steps[].members").type(JsonFieldType.ARRAY) - .description("해당 step에 참여한 참여자 목록"), - fieldWithPath("steps[].actions[].actionId").type(JsonFieldType.NUMBER) - .description("액션 ID"), - fieldWithPath("steps[].actions[].name").type(JsonFieldType.STRING) - .description("참여자 액션일 경우 참여자 이름, 지출 액션일 경우 지출 내역 이름"), - fieldWithPath("steps[].actions[].price").type(JsonFieldType.NUMBER).optional() - .description("참여자 액션일 경우 null, 지출 액션일 경우 지출 금액"), - fieldWithPath("steps[].actions[].sequence").type(JsonFieldType.NUMBER) - .description("액션 순서") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("steps[].type").type(JsonFieldType.STRING) + .description("액션 유형 [BILL, IN, OUT]"), + fieldWithPath("steps[].members").type(JsonFieldType.ARRAY) + .description("해당 step에 참여한 참여자 목록"), + fieldWithPath("steps[].actions[].actionId").type(JsonFieldType.NUMBER) + .description("액션 ID"), + fieldWithPath("steps[].actions[].name").type(JsonFieldType.STRING) + .description("참여자 액션일 경우 참여자 이름, 지출 액션일 경우 지출 내역 이름"), + fieldWithPath("steps[].actions[].price").type(JsonFieldType.NUMBER).optional() + .description("참여자 액션일 경우 null, 지출 액션일 경우 지출 금액"), + fieldWithPath("steps[].actions[].sequence").type(JsonFieldType.NUMBER) + .description("액션 순서"), + fieldWithPath("steps[].actions[].isFixed").type(JsonFieldType.BOOLEAN) + .description("지출 내역의 멤버별 고정 지출 금액 생성 여부") + ) ) ); } @@ -299,7 +301,7 @@ void findActions2() throws Exception { given(eventService.findActions(token)).willReturn(actionAppResponses); mockMvc.perform(get("/api/events/{eventId}/actions/v2", token) - .accept(MediaType.APPLICATION_JSON)) + .accept(MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) .andExpect(jsonPath("$.actions[0].actionId").value(equalTo(1))) @@ -328,23 +330,23 @@ void findActions2() throws Exception { .andDo( document("findActions", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - responseFields( - fieldWithPath("actions[].actionId").type(JsonFieldType.NUMBER) - .description("액션 ID"), - fieldWithPath("actions[].name").type(JsonFieldType.STRING) - .description("참여자 액션일 경우 참여자 이름, 지출 액션일 경우 지출 내역 이름"), - fieldWithPath("actions[].price").type(JsonFieldType.NUMBER).optional() - .description("참여자 액션일 경우 null, 지출 액션일 경우 지출 금액"), - fieldWithPath("actions[].sequence").type(JsonFieldType.NUMBER) - .description("액션 순서"), - fieldWithPath("actions[].type").type(JsonFieldType.STRING) - .description("액션 타입") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("actions[].actionId").type(JsonFieldType.NUMBER) + .description("액션 ID"), + fieldWithPath("actions[].name").type(JsonFieldType.STRING) + .description("참여자 액션일 경우 참여자 이름, 지출 액션일 경우 지출 내역 이름"), + fieldWithPath("actions[].price").type(JsonFieldType.NUMBER).optional() + .description("참여자 액션일 경우 null, 지출 액션일 경우 지출 금액"), + fieldWithPath("actions[].sequence").type(JsonFieldType.NUMBER) + .description("액션 순서"), + fieldWithPath("actions[].type").type(JsonFieldType.STRING) + .description("액션 타입") + ) ) ); } @@ -354,20 +356,20 @@ void findActions2() throws Exception { void authenticateTest() throws Exception { String token = "TOKEN"; mockMvc.perform(post("/api/events/{eventId}/auth", token) - .cookie(EVENT_COOKIE)) + .cookie(EVENT_COOKIE)) .andDo(print()) .andExpect(status().isOk()) .andDo( document("authenticateEvent", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰").optional() - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰").optional() + ) ) ); } diff --git a/server/src/test/java/server/haengdong/domain/action/BillActionTest.java b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java index 13e4bca68..f95558606 100644 --- a/server/src/test/java/server/haengdong/domain/action/BillActionTest.java +++ b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java @@ -3,14 +3,15 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertAll; +import static server.haengdong.support.fixture.Fixture.EVENT1; +import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import server.haengdong.domain.event.Event; import server.haengdong.exception.HaengdongException; -import server.haengdong.support.fixture.Fixture; class BillActionTest { @@ -18,7 +19,7 @@ class BillActionTest { @ParameterizedTest @ValueSource(strings = {"", " ", "1234567890123456789012345678901"}) void validateTitle(String title) { - Event event = Fixture.EVENT1; + Event event = EVENT1; Action action = new Action(event, 1L); Long price = 100L; @@ -31,7 +32,7 @@ void validateTitle(String title) { @ParameterizedTest @ValueSource(longs = {0, 10_000_001, 20_000_000}) void validatePrice(long price) { - Event event = Fixture.EVENT1; + Event event = EVENT1; Action action = new Action(event, 1L); String title = "title"; @@ -43,7 +44,7 @@ void validatePrice(long price) { @DisplayName("지출 내역을 올바르게 생성한다.") @Test void createBillAction() { - Event event = Fixture.EVENT1; + Event event = EVENT1; Action action = new Action(event, 1L); String title = "title"; Long price = 1_000L; @@ -56,4 +57,32 @@ void createBillAction() { () -> assertThat(billAction.getPrice()).isEqualTo(price) ); } + + @DisplayName("지출 액션에 멤버별 고정 금액이 설정되어 있는지 확인한다.") + @Test + void isFixed1() { + BillAction fixedBillAction = new BillAction(new Action(EVENT1, 1L), "인생네컷", 2_000L); + + List<BillActionDetail> unfixedBillActionDetails = List.of( + new BillActionDetail("감자", 1_000L), + new BillActionDetail("고구마", 1_000L) + ); + fixedBillAction.addDetails(unfixedBillActionDetails); + + assertThat(fixedBillAction.isFixed()).isEqualTo(false); + } + + @DisplayName("지출 액션에 멤버별 고정 금액이 설정되어 있는지 확인한다.") + @Test + void isFixed2() { + BillAction fixedBillAction = new BillAction(new Action(EVENT1, 1L), "인생네컷", 5_000L); + + List<BillActionDetail> unfixedBillActionDetails = List.of( + new BillActionDetail("감자", 4_000L), + new BillActionDetail("고구마", 1_000L) + ); + fixedBillAction.addDetails(unfixedBillActionDetails); + + assertThat(fixedBillAction.isFixed()).isEqualTo(true); + } } diff --git a/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java b/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java index 197768a0e..12451435b 100644 --- a/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java +++ b/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java @@ -19,9 +19,21 @@ void createByActions() { Event event = Fixture.EVENT1; List<BillAction> billActions = List.of( new BillAction(new Action(event, 4L), "뽕족", 60_000L), - new BillAction(new Action(event, 6L), "인생맥주", 40_000L), new BillAction(new Action(event, 7L), "인생네컷", 20_000L) ); + billActions.get(0).addDetails( + List.of( + new BillActionDetail("소하", 10_000L), + new BillActionDetail("감자", 40_000L), + new BillActionDetail("쿠키", 10_000L) + ) + ); + billActions.get(1).addDetails( + List.of( + new BillActionDetail("소하", 5_000L), + new BillActionDetail("쿠키", 15_000L) + ) + ); List<MemberAction> memberActions = List.of( new MemberAction(new Action(event, 1L), "소하", IN, 1L), new MemberAction(new Action(event, 2L), "감자", IN, 1L), @@ -34,9 +46,9 @@ void createByActions() { assertThat(memberBillReport.getReports()) .containsAllEntriesOf( Map.of( - "감자", 20_000L, - "쿠키", 50_000L, - "소하", 50_000L + "감자", 40_000L, + "쿠키", 25_000L, + "소하", 15_000L ) ); } From b167550dc859824dcdf74b4d5ec3813ba09a009d Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Mon, 19 Aug 2024 14:42:53 +0900 Subject: [PATCH 148/178] =?UTF-8?q?feat:=20=EC=B0=B8=EC=97=AC=EC=9E=90=20?= =?UTF-8?q?=EA=B0=9C=EB=B3=84=20=EC=A7=80=EC=B6=9C=20=EA=B8=88=EC=95=A1=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84=20(#378)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 참여자 개별 지출 금액 수정 기능 구현 * refactor: BillActionDetailService 코드 리팩터링 * docs: restdocs 작성 * feat: 참여자별 지출 금액 조회 기능 구현 * docs: index.adoc에 billActionDetail.adoc 추가 * refactor: 충돌 해결 --- .../src/docs/asciidoc/billActionDetail.adoc | 93 +++++++++++++ server/src/docs/asciidoc/index.adoc | 17 +-- .../application/BillActionDetailService.java | 66 ++++++++++ .../application/BillActionService.java | 2 +- .../BillActionDetailUpdateAppRequest.java | 7 + .../BillActionDetailsUpdateAppRequest.java | 8 ++ .../response/BillActionDetailAppResponse.java | 13 ++ .../BillActionDetailsAppResponse.java | 14 ++ .../haengdong/domain/action/BillAction.java | 4 + .../domain/action/BillActionDetail.java | 23 +++- .../action/BillActionDetailRepository.java | 8 +- .../exception/HaengdongErrorCode.java | 5 +- .../BillActionDetailController.java | 30 +++++ .../BillActionDetailUpdateRequest.java | 18 +++ .../BillActionDetailsUpdateRequest.java | 15 +++ .../response/BillActionDetailResponse.java | 13 ++ .../response/BillActionDetailsResponse.java | 16 +++ .../BillActionDetailServiceTest.java | 111 ++++++++++++++++ .../application/BillActionServiceTest.java | 2 +- .../application/MemberActionServiceTest.java | 4 +- .../BillActionDetailControllerDocsTest.java | 122 ++++++++++++++++++ .../BillActionDetailControllerTest.java | 56 ++++++++ .../presentation/ControllerTestSupport.java | 8 +- 23 files changed, 632 insertions(+), 23 deletions(-) create mode 100644 server/src/docs/asciidoc/billActionDetail.adoc create mode 100644 server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/BillActionDetailsUpdateAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/BillActionDetailsAppResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/BillActionDetailsResponse.java create mode 100644 server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java create mode 100644 server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java diff --git a/server/src/docs/asciidoc/billActionDetail.adoc b/server/src/docs/asciidoc/billActionDetail.adoc new file mode 100644 index 000000000..a8f19f21b --- /dev/null +++ b/server/src/docs/asciidoc/billActionDetail.adoc @@ -0,0 +1,93 @@ +== 지출 상세 + +=== 지출 상세 조회 + +operation::findBillActionDetailsTest[snippets="path-parameters,http-request,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code": "EVENT_NOT_FOUND", + "message": "존재하지 않는 행사입니다." + }, + { + "code": "BILL_ACTION_NOT_FOUND", + "message": "존재하지 않는 지출 액션입니다." + }, + { + "code": "BILL_ACTION_DETAIL_NOT_FOUND", + "message": "존재하지 않는 참여자 지출입니다." + }, + { + "code": "TOKEN_NOT_FOUND", + "message": "토큰이 존재하지 않습니다." + }, + { + "code": "TOKEN_EXPIRED", + "message": "만료된 토큰입니다." + }, + { + "code": "TOKEN_INVALID", + "message": "유효하지 않은 토큰입니다." + }, + { + "code": "FORBIDDEN", + "message": "접근할 수 없는 행사입니다." + } +] +---- + +=== 지출 상세 수정 + +operation::updateBillActionDetailsTest[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code": "REQUEST_EMPTY", + "message": "멤버 이름은 공백일 수 없습니다." + }, + { + "code": "REQUEST_EMPTY", + "message": "지출 금액은 공백일 수 없습니다." + }, + { + "code": "EVENT_NOT_FOUND", + "message": "존재하지 않는 행사입니다." + }, + { + "code": "BILL_ACTION_NOT_FOUND", + "message": "존재하지 않는 지출 액션입니다." + }, + { + "code": "BILL_ACTION_DETAIL_NOT_FOUND", + "message": "존재하지 않는 참여자 지출입니다." + }, + { + "code": "BILL_ACTION_PRICE_NOT_MATCHED", + "message": "지출 총액이 일치하지 않습니다." + }, + { + "code": "TOKEN_NOT_FOUND", + "message": "토큰이 존재하지 않습니다." + }, + { + "code": "TOKEN_EXPIRED", + "message": "만료된 토큰입니다." + }, + { + "code": "TOKEN_INVALID", + "message": "유효하지 않은 토큰입니다." + }, + { + "code": "FORBIDDEN", + "message": "접근할 수 없는 행사입니다." + } +] +---- diff --git a/server/src/docs/asciidoc/index.adoc b/server/src/docs/asciidoc/index.adoc index 3039f2bbf..8e1bcd2d0 100644 --- a/server/src/docs/asciidoc/index.adoc +++ b/server/src/docs/asciidoc/index.adoc @@ -1,18 +1,15 @@ -:source-highlighter: highlightjs -:hardbreaks: -:toc: left -:doctype: book -:icons: font -:toc-title: 전체 API 목록 -:toclevels: 2 -:sectlinks: +ifndef::snippets[] +:snippets: ../../build/generated-snippets +endif::[] += 행동대장 +:source-highlighter: highlightjs :hardbreaks: +:toc: left :doctype: book :icons: font :toc-title: 전체 API 목록 :toclevels: 2 :sectlinks: :sectnums: :sectnumlevels: 2 -= 행동대장 include::{docdir}/event.adoc[] include::{docdir}/memberBillReport.adoc[] include::{docdir}/memberAction.adoc[] include::{docdir}/billAction.adoc[] - +include::{docdir}/billActionDetail.adoc[] diff --git a/server/src/main/java/server/haengdong/application/BillActionDetailService.java b/server/src/main/java/server/haengdong/application/BillActionDetailService.java index 14a7e8a06..5d4cf335a 100644 --- a/server/src/main/java/server/haengdong/application/BillActionDetailService.java +++ b/server/src/main/java/server/haengdong/application/BillActionDetailService.java @@ -1,12 +1,78 @@ package server.haengdong.application; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.BillActionDetailUpdateAppRequest; +import server.haengdong.application.request.BillActionDetailsUpdateAppRequest; +import server.haengdong.application.response.BillActionDetailsAppResponse; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; +import server.haengdong.domain.action.BillActionDetailRepository; import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; @RequiredArgsConstructor +@Transactional(readOnly = true) @Service public class BillActionDetailService { + private final BillActionDetailRepository billActionDetailRepository; private final BillActionRepository billActionRepository; + + public BillActionDetailsAppResponse findBillActionDetails(String token, Long actionId) { + BillAction billAction = billActionRepository.findByAction_Id(actionId) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); + validateToken(token, billAction); + + List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(billAction); + + return BillActionDetailsAppResponse.of(billActionDetails); + } + + @Transactional + public void updateBillActionDetails(String token, Long actionId, BillActionDetailsUpdateAppRequest request) { + BillAction billAction = billActionRepository.findByAction_Id(actionId) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); + + List<BillActionDetailUpdateAppRequest> billActionDetailUpdateAppRequests = request.billActionDetailUpdateAppRequests(); + + validateToken(token, billAction); + validateTotalPrice(billActionDetailUpdateAppRequests, billAction); + + List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(billAction); + + for (BillActionDetailUpdateAppRequest updateRequest : billActionDetailUpdateAppRequests) { + BillActionDetail detailToUpdate = billActionDetails.stream() + .filter(detail -> detail.isSameName(updateRequest.name())) + .findFirst() + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_DETAIL_NOT_FOUND)); + + detailToUpdate.updatePrice(updateRequest.price()); + } + } + + private void validateToken(String token, BillAction billAction) { + Event event = billAction.getEvent(); + if (event.isTokenMismatch(token)) { + throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND); + } + } + + private void validateTotalPrice(List<BillActionDetailUpdateAppRequest> billActionDetailUpdateAppRequests, + BillAction billAction) { + Long requestsPriceSum = calculateUpdatePriceSum(billActionDetailUpdateAppRequests); + if (!billAction.isSamePrice(requestsPriceSum)) { + throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_PRICE_NOT_MATCHED); + } + } + + private Long calculateUpdatePriceSum(List<BillActionDetailUpdateAppRequest> billActionDetailUpdateAppRequests) { + return billActionDetailUpdateAppRequests.stream() + .map(BillActionDetailUpdateAppRequest::price) + .reduce(0L, Long::sum); + } } diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java index 803a21055..95717d825 100644 --- a/server/src/main/java/server/haengdong/application/BillActionService.java +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -75,7 +75,7 @@ public void updateBillAction(String token, Long actionId, BillActionUpdateAppReq private void resetBillActionDetail(BillAction billAction, Long updatePrice) { if (billAction.getPrice() != updatePrice) { - List<BillActionDetail> billActionDetails = billActionDetailRepository.findByBillAction(billAction); + List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(billAction); int memberCount = billActionDetails.size(); if (memberCount != 0) { Long eachPrice = updatePrice / memberCount; diff --git a/server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java new file mode 100644 index 000000000..a815e4afa --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java @@ -0,0 +1,7 @@ +package server.haengdong.application.request; + +public record BillActionDetailUpdateAppRequest( + String name, + Long price +) { +} diff --git a/server/src/main/java/server/haengdong/application/request/BillActionDetailsUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionDetailsUpdateAppRequest.java new file mode 100644 index 000000000..1fe19798e --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/BillActionDetailsUpdateAppRequest.java @@ -0,0 +1,8 @@ +package server.haengdong.application.request; + +import java.util.List; + +public record BillActionDetailsUpdateAppRequest( + List<BillActionDetailUpdateAppRequest> billActionDetailUpdateAppRequests +) { +} diff --git a/server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java b/server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java new file mode 100644 index 000000000..1ddb51671 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java @@ -0,0 +1,13 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.action.BillActionDetail; + +public record BillActionDetailAppResponse( + String name, + Long price +) { + + public static BillActionDetailAppResponse of(BillActionDetail billActionDetail) { + return new BillActionDetailAppResponse(billActionDetail.getMemberName(), billActionDetail.getPrice()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/BillActionDetailsAppResponse.java b/server/src/main/java/server/haengdong/application/response/BillActionDetailsAppResponse.java new file mode 100644 index 000000000..061f07816 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/BillActionDetailsAppResponse.java @@ -0,0 +1,14 @@ +package server.haengdong.application.response; + +import java.util.List; +import java.util.stream.Collectors; +import server.haengdong.domain.action.BillActionDetail; + +public record BillActionDetailsAppResponse(List<BillActionDetailAppResponse> billActionDetailAppResponses) { + + public static BillActionDetailsAppResponse of(List<BillActionDetail> billActionDetails) { + return billActionDetails.stream() + .map(BillActionDetailAppResponse::of) + .collect(Collectors.collectingAndThen(Collectors.toList(), BillActionDetailsAppResponse::new)); + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/BillAction.java b/server/src/main/java/server/haengdong/domain/action/BillAction.java index 65db11734..0b35040e6 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillAction.java +++ b/server/src/main/java/server/haengdong/domain/action/BillAction.java @@ -77,6 +77,10 @@ public void update(String title, Long price) { this.price = price; } + public boolean isSamePrice(Long price) { + return this.price.equals(price); + } + public Long getSequence() { return action.getSequence(); } diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java index 550499aa5..06847c2bb 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java @@ -31,15 +31,14 @@ public BillActionDetail(String memberName, Long price) { this.price = price; } - public void setBillAction(BillAction billAction) { + public BillActionDetail(BillAction billAction, String memberName, Long price) { this.billAction = billAction; + this.memberName = memberName; + this.price = price; } - public boolean hasMemberName(String memberName) { - return this.memberName.equals(memberName); - } - - public BillActionDetail(BillAction billAction, String memberName, Long price) { + public BillActionDetail(Long id, BillAction billAction, String memberName, Long price) { + this.id = id; this.billAction = billAction; this.memberName = memberName; this.price = price; @@ -48,4 +47,16 @@ public BillActionDetail(BillAction billAction, String memberName, Long price) { public void updatePrice(Long price) { this.price = price; } + + public boolean hasMemberName(String memberName) { + return this.memberName.equals(memberName); + } + + public boolean isSameName(String memberName) { + return this.memberName.equals(memberName); + } + + public void setBillAction(BillAction billAction) { + this.billAction = billAction; + } } diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java index 5d74462ff..35b331bee 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java @@ -2,13 +2,19 @@ import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import server.haengdong.domain.event.Event; @Repository public interface BillActionDetailRepository extends JpaRepository<BillActionDetail, Long> { - List<BillActionDetail> findByBillAction(BillAction billAction); + @Query(""" + select bd + from BillActionDetail bd + where bd.billAction = :billAction + """) + List<BillActionDetail> findAllByBillAction(BillAction billAction); void deleteAllByBillAction(BillAction billAction); diff --git a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java index 4020879d2..ff61d4898 100644 --- a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java +++ b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java @@ -35,6 +35,8 @@ public enum HaengdongErrorCode { BillAction.MIN_TITLE_LENGTH, BillAction.MAX_TITLE_LENGTH)), BILL_ACTION_PRICE_INVALID(String.format("지출 금액은 %,d 이하의 자연수여야 합니다.", BillAction.MAX_PRICE)), + BILL_ACTION_DETAIL_NOT_FOUND("존재하지 않는 참여자 지출입니다."), + BILL_ACTION_PRICE_NOT_MATCHED("지출 총액이 일치하지 않습니다."), /* Authentication */ @@ -55,7 +57,8 @@ public enum HaengdongErrorCode { MESSAGE_NOT_READABLE("읽을 수 없는 요청입니다."), REQUEST_METHOD_NOT_SUPPORTED("지원하지 않는 요청 메서드입니다."), NO_RESOURCE_REQUEST("존재하지 않는 자원입니다."), - INTERNAL_SERVER_ERROR("서버 내부에서 에러가 발생했습니다."); + INTERNAL_SERVER_ERROR("서버 내부에서 에러가 발생했습니다."), + ; private final String message; diff --git a/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java b/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java index 376b4ff26..5602e6777 100644 --- a/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java +++ b/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java @@ -1,12 +1,42 @@ package server.haengdong.presentation; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import server.haengdong.application.BillActionDetailService; +import server.haengdong.application.response.BillActionDetailsAppResponse; +import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; +import server.haengdong.presentation.response.BillActionDetailsResponse; @RequiredArgsConstructor @RestController public class BillActionDetailController { private final BillActionDetailService billActionDetailService; + + @GetMapping("/api/events/{eventId}/bill-actions/{actionId}/fixed") + public ResponseEntity<BillActionDetailsResponse> findBillActionDetails( + @PathVariable("eventId") String token, + @PathVariable("actionId") Long actionId + ) { + BillActionDetailsAppResponse appResponse = billActionDetailService.findBillActionDetails(token, actionId); + + return ResponseEntity.ok(BillActionDetailsResponse.of(appResponse)); + } + + @PutMapping("/api/events/{eventId}/bill-actions/{actionId}/fixed") + public ResponseEntity<Void> updateBillActionDetails( + @PathVariable("eventId") String token, + @PathVariable("actionId") Long actionId, + @Valid @RequestBody BillActionDetailsUpdateRequest request + ) { + billActionDetailService.updateBillActionDetails(token, actionId, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } } diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java new file mode 100644 index 000000000..2988f2ace --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java @@ -0,0 +1,18 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import server.haengdong.application.request.BillActionDetailUpdateAppRequest; + +public record BillActionDetailUpdateRequest( + + @NotBlank(message = "맴버 이름은 공백일 수 없습니다.") + String name, + + @NotNull(message = "지출 금액은 공백일 수 없습니다.") + Long price +) { + public BillActionDetailUpdateAppRequest toAppRequest() { + return new BillActionDetailUpdateAppRequest(this.name, this.price); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java new file mode 100644 index 000000000..2cd79b61d --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java @@ -0,0 +1,15 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.Valid; +import java.util.List; +import server.haengdong.application.request.BillActionDetailsUpdateAppRequest; + +public record BillActionDetailsUpdateRequest( + @Valid List<BillActionDetailUpdateRequest> members +) { + public BillActionDetailsUpdateAppRequest toAppRequest() { + return new BillActionDetailsUpdateAppRequest(members.stream() + .map(BillActionDetailUpdateRequest::toAppRequest) + .toList()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java b/server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java new file mode 100644 index 000000000..46d56438c --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java @@ -0,0 +1,13 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.BillActionDetailAppResponse; + +public record BillActionDetailResponse( + String name, + Long price +) { + + public static BillActionDetailResponse of(BillActionDetailAppResponse billActionDetailAppResponse) { + return new BillActionDetailResponse(billActionDetailAppResponse.name(), billActionDetailAppResponse.price()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/BillActionDetailsResponse.java b/server/src/main/java/server/haengdong/presentation/response/BillActionDetailsResponse.java new file mode 100644 index 000000000..182e76db6 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/BillActionDetailsResponse.java @@ -0,0 +1,16 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import java.util.stream.Collectors; +import server.haengdong.application.response.BillActionDetailsAppResponse; + +public record BillActionDetailsResponse( + List<BillActionDetailResponse> members +) { + + public static BillActionDetailsResponse of(BillActionDetailsAppResponse billActionDetailsAppResponse) { + return billActionDetailsAppResponse.billActionDetailAppResponses().stream() + .map(BillActionDetailResponse::of) + .collect(Collectors.collectingAndThen(Collectors.toList(), BillActionDetailsResponse::new)); + } +} diff --git a/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java new file mode 100644 index 000000000..3e7aee56e --- /dev/null +++ b/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java @@ -0,0 +1,111 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.tuple; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import server.haengdong.application.request.BillActionDetailUpdateAppRequest; +import server.haengdong.application.request.BillActionDetailsUpdateAppRequest; +import server.haengdong.application.response.BillActionDetailAppResponse; +import server.haengdong.application.response.BillActionDetailsAppResponse; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; +import server.haengdong.domain.action.BillActionDetailRepository; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class BillActionDetailServiceTest extends ServiceTestSupport { + + @Autowired + private BillActionDetailService billActionDetailService; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillActionRepository billActionRepository; + + @Autowired + private BillActionDetailRepository billActionDetailRepository; + + @DisplayName("참여자별 지출 금액을 조회한다.") + @Test + void findBillActionDetailsTest() { + Event event1 = Fixture.EVENT1; + eventRepository.save(event1); + Action action = new Action(event1, 1L); + BillAction billAction = new BillAction(action, "뽕족", 10000L); + billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(1L, billAction, "토다리", 6000L); + BillActionDetail billActionDetail2 = new BillActionDetail(2L, billAction, "쿠키", 4000L); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); + + BillActionDetailsAppResponse response = billActionDetailService.findBillActionDetails( + event1.getToken(), action.getId()); + + assertThat(response.billActionDetailAppResponses()).hasSize(2) + .extracting(BillActionDetailAppResponse::name, BillActionDetailAppResponse::price) + .containsExactly( + tuple("토다리", 6000L), + tuple("쿠키", 4000L) + ); + } + + @DisplayName("지출 금액 수정 요청의 총합이 지출 금액과 일치하지 않으면 예외가 발생한다.") + @Test + void updateBillActionDetailsTest1() { + Event event1 = Fixture.EVENT1; + eventRepository.save(event1); + Action action = new Action(event1, 1L); + BillAction billAction = new BillAction(action, "뽕족", 10000L); + billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(1L, billAction, "토다리", 5000L); + BillActionDetail billActionDetail2 = new BillActionDetail(2L, billAction, "쿠키", 5000L); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); + + BillActionDetailsUpdateAppRequest request = new BillActionDetailsUpdateAppRequest(List.of( + new BillActionDetailUpdateAppRequest("토다리", 3000L), + new BillActionDetailUpdateAppRequest("쿠키", 4000L) + )); + assertThatCode( + () -> billActionDetailService.updateBillActionDetails(event1.getToken(), action.getId(), request)) + .isInstanceOf(HaengdongException.class) + .hasMessage("지출 총액이 일치하지 않습니다."); + } + + @DisplayName("지출 고정 금액을 수정한다.") + @Test + void updateBillActionDetailsTest2() { + Event event1 = Fixture.EVENT1; + eventRepository.save(event1); + Action action = new Action(event1, 1L); + BillAction billAction = new BillAction(action, "뽕족", 10000L); + billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(1L, billAction, "토다리", 5000L); + BillActionDetail billActionDetail2 = new BillActionDetail(2L, billAction, "쿠키", 5000L); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); + + BillActionDetailsUpdateAppRequest request = new BillActionDetailsUpdateAppRequest(List.of( + new BillActionDetailUpdateAppRequest("토다리", 3000L), + new BillActionDetailUpdateAppRequest("쿠키", 7000L) + )); + billActionDetailService.updateBillActionDetails(event1.getToken(), action.getId(), request); + + List<BillActionDetail> results = billActionDetailRepository.findAll(); + + assertThat(results).hasSize(2) + .extracting(BillActionDetail::getMemberName, BillActionDetail::getPrice) + .containsExactly( + tuple("토다리", 3000L), + tuple("쿠키", 7000L) + ); + } +} diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java index be535411d..c0e588288 100644 --- a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java @@ -174,7 +174,7 @@ void updateBillAction2() { billActionService.updateBillAction(event.getToken(), actionId, request); BillAction updatedBillAction = billActionRepository.findById(savedBillAction.getId()).get(); - List<BillActionDetail> billActionDetails = billActionDetailRepository.findByBillAction(updatedBillAction); + List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(updatedBillAction); assertThat(billActionDetails).hasSize(4) .extracting("memberName", "price") diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java index 14a7d4225..06368a9fb 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java @@ -153,7 +153,7 @@ void deleteMember1() { memberActionService.deleteMember(event.getToken(), "쿠키"); - List<BillActionDetail> billActionDetails = billActionDetailRepository.findByBillAction(billAction); + List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(billAction); assertThat(billActionDetails).hasSize(2) .extracting("memberName", "price") @@ -226,7 +226,7 @@ void deleteMemberAction1() { billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3)); memberActionService.deleteMemberAction(event.getToken(), targetAction.getId()); - List<BillActionDetail> billActionDetails = billActionDetailRepository.findByBillAction(billAction); + List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(billAction); assertThat(billActionDetails).hasSize(4) .extracting("memberName", "price") diff --git a/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java new file mode 100644 index 000000000..3116cba5e --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java @@ -0,0 +1,122 @@ +package server.haengdong.docs; + +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; +import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.restdocs.payload.JsonFieldType; +import server.haengdong.application.BillActionDetailService; +import server.haengdong.application.response.BillActionDetailAppResponse; +import server.haengdong.application.response.BillActionDetailsAppResponse; +import server.haengdong.presentation.BillActionDetailController; +import server.haengdong.presentation.request.BillActionDetailUpdateRequest; +import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; + +public class BillActionDetailControllerDocsTest extends RestDocsSupport { + + private final BillActionDetailService billActionDetailService = mock(BillActionDetailService.class); + + @Override + protected Object initController() { + return new BillActionDetailController(billActionDetailService); + } + + @DisplayName("참여자별 지출 금액을 조회한다.") + @Test + void findBillActionDetailsTest() throws Exception { + BillActionDetailsAppResponse appResponse = new BillActionDetailsAppResponse( + List.of(new BillActionDetailAppResponse("토다리", 1000L))); + given(billActionDetailService.findBillActionDetails(anyString(), anyLong())) + .willReturn(appResponse); + + mockMvc.perform(get("/api/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").isArray()) + .andExpect(jsonPath("$.members[0].name").value("토다리")) + .andExpect(jsonPath("$.members[0].price").value(1000L)) + .andDo( + document("findBillActionDetailsTest", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("actionId").description("액션 ID") + ), requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), responseFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("전체 정산 수정 요청 목록"), + fieldWithPath("members[0].name").type(JsonFieldType.STRING) + .description("참여자 이름"), + fieldWithPath("members[0].price").type(JsonFieldType.NUMBER) + .description("참여자 정산 금액") + ) + ) + ); + } + + @DisplayName("참여자별 지출 금액을 수정한다.") + @Test + void updateBillActionDetailsTest() throws Exception { + List<BillActionDetailUpdateRequest> billActionDetailUpdateRequests = List.of( + new BillActionDetailUpdateRequest("소하", 10000L), + new BillActionDetailUpdateRequest("웨디", 20000L) + ); + BillActionDetailsUpdateRequest request = new BillActionDetailsUpdateRequest( + billActionDetailUpdateRequests); + + String json = objectMapper.writeValueAsString(request); + + mockMvc.perform(put("/api/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L) + .cookie(EVENT_COOKIE) + .contentType(MediaType.APPLICATION_JSON) + .content(json)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("updateBillActionDetailsTest", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("actionId").description("액션 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), + requestFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("전체 정산 수정 요청 목록"), + fieldWithPath("members[0].name").type(JsonFieldType.STRING) + .description("참여자 이름"), + fieldWithPath("members[0].price").type(JsonFieldType.NUMBER) + .description("참여자 정산 금액") + ) + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java new file mode 100644 index 000000000..f098153d4 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java @@ -0,0 +1,56 @@ +package server.haengdong.presentation; + +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import server.haengdong.application.response.BillActionDetailAppResponse; +import server.haengdong.application.response.BillActionDetailsAppResponse; +import server.haengdong.presentation.request.BillActionDetailUpdateRequest; +import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; + +class BillActionDetailControllerTest extends ControllerTestSupport { + + @DisplayName("참여자별 지출 금액을 조회한다.") + @Test + void findBillActionDetails() throws Exception { + BillActionDetailsAppResponse appResponse = new BillActionDetailsAppResponse( + List.of(new BillActionDetailAppResponse("토다리", 1000L))); + given(billActionDetailService.findBillActionDetails(anyString(), anyLong())) + .willReturn(appResponse); + + mockMvc.perform(get("/api/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").isArray()) + .andExpect(jsonPath("$.members[0].name").value("토다리")) + .andExpect(jsonPath("$.members[0].price").value(1000L)); + } + + @DisplayName("참여자별 지출 금액을 수정한다.") + @Test + void updateBillActionDetailsTest() throws Exception { + List<BillActionDetailUpdateRequest> billActionDetailUpdateRequests = List.of( + new BillActionDetailUpdateRequest("소하", 10000L), + new BillActionDetailUpdateRequest("웨디", 20000L) + ); + BillActionDetailsUpdateRequest request = new BillActionDetailsUpdateRequest( + billActionDetailUpdateRequests); + + String json = objectMapper.writeValueAsString(request); + + mockMvc.perform(put("/api/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L) + .contentType(MediaType.APPLICATION_JSON) + .content(json)) + .andDo(print()) + .andExpect(status().isOk()); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java b/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java index a9897d9f0..46489b1a5 100644 --- a/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java +++ b/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java @@ -10,6 +10,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import server.haengdong.application.ActionService; import server.haengdong.application.AuthService; +import server.haengdong.application.BillActionDetailService; import server.haengdong.application.BillActionService; import server.haengdong.application.EventService; import server.haengdong.application.MemberActionService; @@ -19,7 +20,8 @@ EventController.class, ActionController.class, BillActionController.class, - MemberActionController.class + MemberActionController.class, + BillActionDetailController.class }, excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {WebMvcConfigurer.class})} ) @@ -27,6 +29,7 @@ abstract class ControllerTestSupport { @Autowired protected MockMvc mockMvc; + @Autowired protected ObjectMapper objectMapper; @@ -44,4 +47,7 @@ abstract class ControllerTestSupport { @MockBean protected BillActionService billActionService; + + @MockBean + protected BillActionDetailService billActionDetailService; } From 4dbc2076b2dbd271cfaf29a30cec1f429760875b Mon Sep 17 00:00:00 2001 From: Juhwan Kim <13selfesteem91@naver.com> Date: Mon, 19 Aug 2024 15:34:52 +0900 Subject: [PATCH 149/178] =?UTF-8?q?feat:=20=EC=97=90=EB=9F=AC=EB=A5=BC=20?= =?UTF-8?q?=EC=9E=AC=ED=98=84=ED=95=A0=20=EC=88=98=20=EC=9E=88=EB=8A=94=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EB=A1=9C=20=EC=88=98=EC=A0=95=20(#392)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 로깅에 요청 정보 포함 * feat: 개발 환경 ddl update로 변경 --- .../haengdong/config/AdminInterceptor.java | 3 +- .../exception/GlobalExceptionHandler.java | 31 +++++++++++++++---- server/src/main/resources/config | 2 +- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/server/src/main/java/server/haengdong/config/AdminInterceptor.java b/server/src/main/java/server/haengdong/config/AdminInterceptor.java index c78cd854e..a0542ed46 100644 --- a/server/src/main/java/server/haengdong/config/AdminInterceptor.java +++ b/server/src/main/java/server/haengdong/config/AdminInterceptor.java @@ -23,8 +23,6 @@ public AdminInterceptor(AuthService authService, AuthenticationExtractor authent @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { - log.debug("login request = {}", request.getRequestURI()); - String requestURI = request.getRequestURI(); if (requestURI.endsWith("/login")) { @@ -46,6 +44,7 @@ private void validateToken(HttpServletRequest request) { String tokenEventId = authService.findEventIdByToken(token); String eventId = request.getRequestURI().split("/")[3]; if (!tokenEventId.equals(eventId)) { + log.warn("[행사 접근 불가] Cookie EventId = {}, URL EventId = {}", tokenEventId, eventId); throw new AuthenticationException(HaengdongErrorCode.FORBIDDEN); } } diff --git a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java index 7ed01c3c6..4d7dff45f 100644 --- a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java +++ b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java @@ -1,5 +1,8 @@ package server.haengdong.exception; +import jakarta.servlet.http.HttpServletRequest; +import java.io.BufferedReader; +import java.io.IOException; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; @@ -15,9 +18,16 @@ @RestControllerAdvice public class GlobalExceptionHandler { + private static final String LOG_FORMAT = """ + + [Request URI] {} {} + [Request Body] {} + [Error Message] {} + """; + @ExceptionHandler(AuthenticationException.class) - public ResponseEntity<ErrorResponse> authenticationException(AuthenticationException e) { - log.warn(e.getMessage(), e); + public ResponseEntity<ErrorResponse> authenticationException(HttpServletRequest req, AuthenticationException e) { + log.warn(LOG_FORMAT, req.getMethod(), req.getRequestURI(), getRequestBody(req), e.getMessage(), e); return ResponseEntity.status(HttpStatus.UNAUTHORIZED) .body(ErrorResponse.of(e.getErrorCode())); } @@ -55,16 +65,25 @@ public ResponseEntity<ErrorResponse> handleMethodArgumentNotValidException(Metho } @ExceptionHandler(HaengdongException.class) - public ResponseEntity<ErrorResponse> haengdongException(HaengdongException e) { - log.warn(e.getMessage(), e); + public ResponseEntity<ErrorResponse> haengdongException(HttpServletRequest req, HaengdongException e) { + log.warn(LOG_FORMAT, req.getMethod(), req.getRequestURI(), getRequestBody(req), e.getMessage(), e); return ResponseEntity.badRequest() .body(ErrorResponse.of(e.getErrorCode())); } @ExceptionHandler(Exception.class) - public ResponseEntity<ErrorResponse> handleException(Exception e) { - log.error(e.getMessage(), e); + public ResponseEntity<ErrorResponse> handleException(HttpServletRequest req, Exception e) { + log.error(LOG_FORMAT, req.getMethod(), req.getRequestURI(), getRequestBody(req), e.getMessage(), e); return ResponseEntity.internalServerError() .body(ErrorResponse.of(HaengdongErrorCode.INTERNAL_SERVER_ERROR)); } + + private String getRequestBody(HttpServletRequest req) { + try (BufferedReader reader = req.getReader()) { + return reader.lines().collect(Collectors.joining(System.lineSeparator())); + } catch (IOException e) { + log.error("Failed to read request body", e); + return ""; + } + } } diff --git a/server/src/main/resources/config b/server/src/main/resources/config index 141eb40e8..e3e68ba63 160000 --- a/server/src/main/resources/config +++ b/server/src/main/resources/config @@ -1 +1 @@ -Subproject commit 141eb40e871cc9c3e172af46db29d90ac6448180 +Subproject commit e3e68ba63b49a7f6eaae8ccbd8c8af653ba34f3b From 87002598d850fb239ebfb9e92638fa40551f54d8 Mon Sep 17 00:00:00 2001 From: Juhwan Kim <13selfesteem91@naver.com> Date: Mon, 19 Aug 2024 16:20:52 +0900 Subject: [PATCH 150/178] =?UTF-8?q?feat:=20=EC=98=88=EC=99=B8=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EB=B0=8F=20=EB=A1=9C=EA=B9=85=20=ED=98=95=EC=8B=9D?= =?UTF-8?q?=20=EC=88=98=EC=A0=95=20(#394)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 리스트 형태의 요청 바디에 null을 넣으면 500이 뜨는 에러 수정 * feat: 로그를 json 형태로 수정 --- .../haengdong/exception/GlobalExceptionHandler.java | 9 +++++---- .../haengdong/presentation/BillActionController.java | 2 +- .../request/BillActionDetailsUpdateRequest.java | 7 ++++--- .../presentation/request/BillActionsSaveRequest.java | 3 ++- .../presentation/request/MemberActionsSaveRequest.java | 3 +++ .../presentation/request/MemberNamesUpdateRequest.java | 7 ++++--- 6 files changed, 19 insertions(+), 12 deletions(-) diff --git a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java index 4d7dff45f..ec8e4cba0 100644 --- a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java +++ b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java @@ -19,10 +19,11 @@ public class GlobalExceptionHandler { private static final String LOG_FORMAT = """ - - [Request URI] {} {} - [Request Body] {} - [Error Message] {} + { + "RequestURI": "{} {}", + "RequestBody": "{}", + "ErrorMessage": "{}" + } """; @ExceptionHandler(AuthenticationException.class) diff --git a/server/src/main/java/server/haengdong/presentation/BillActionController.java b/server/src/main/java/server/haengdong/presentation/BillActionController.java index 94cd1666b..56e99337d 100644 --- a/server/src/main/java/server/haengdong/presentation/BillActionController.java +++ b/server/src/main/java/server/haengdong/presentation/BillActionController.java @@ -22,7 +22,7 @@ public class BillActionController { @PostMapping("/api/events/{eventId}/bill-actions") public ResponseEntity<Void> saveAllBillAction( @PathVariable("eventId") String token, - @RequestBody @Valid BillActionsSaveRequest request + @Valid @RequestBody BillActionsSaveRequest request ) { billActionService.saveAllBillAction(token, request.toAppRequests()); diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java index 2cd79b61d..fafbb8fd7 100644 --- a/server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java @@ -1,15 +1,16 @@ package server.haengdong.presentation.request; import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; import java.util.List; import server.haengdong.application.request.BillActionDetailsUpdateAppRequest; public record BillActionDetailsUpdateRequest( - @Valid List<BillActionDetailUpdateRequest> members + @Valid @NotEmpty List<BillActionDetailUpdateRequest> members ) { public BillActionDetailsUpdateAppRequest toAppRequest() { return new BillActionDetailsUpdateAppRequest(members.stream() - .map(BillActionDetailUpdateRequest::toAppRequest) - .toList()); + .map(BillActionDetailUpdateRequest::toAppRequest) + .toList()); } } diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java index 42bf86149..6727d4cf1 100644 --- a/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java @@ -1,12 +1,13 @@ package server.haengdong.presentation.request; import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; import java.util.List; import server.haengdong.application.request.BillActionAppRequest; public record BillActionsSaveRequest( - @Valid List<BillActionSaveRequest> actions + @Valid @NotEmpty List<BillActionSaveRequest> actions ) { public List<BillActionAppRequest> toAppRequests() { diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java index 828fc7b4c..41e95cc3c 100644 --- a/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java @@ -1,11 +1,14 @@ package server.haengdong.presentation.request; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; import java.util.List; import server.haengdong.application.request.MemberActionSaveAppRequest; import server.haengdong.application.request.MemberActionsSaveAppRequest; public record MemberActionsSaveRequest( + + @NotEmpty List<String> members, @NotBlank(message = "멤버 액션은 공백일 수 없습니다.") diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java index c67e1b699..872aa55de 100644 --- a/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java @@ -1,16 +1,17 @@ package server.haengdong.presentation.request; import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; import java.util.List; import server.haengdong.application.request.MemberNamesUpdateAppRequest; public record MemberNamesUpdateRequest( - @Valid List<MemberNameUpdateRequest> members + @Valid @NotEmpty List<MemberNameUpdateRequest> members ) { public MemberNamesUpdateAppRequest toAppRequest() { return new MemberNamesUpdateAppRequest(members.stream() - .map(MemberNameUpdateRequest::toAppRequest) - .toList()); + .map(MemberNameUpdateRequest::toAppRequest) + .toList()); } } From 07f4bf3b5ad5d92a3b5ad2c111821070178833b9 Mon Sep 17 00:00:00 2001 From: Juhwan Kim <13selfesteem91@naver.com> Date: Mon, 19 Aug 2024 16:55:45 +0900 Subject: [PATCH 151/178] =?UTF-8?q?feat:=20=EC=98=88=EC=99=B8=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EB=B0=8F=20=EB=A1=9C=EA=B9=85=20=ED=98=95=EC=8B=9D?= =?UTF-8?q?=20=EC=88=98=EC=A0=95=20(#395)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 리스트 형태의 요청 바디에 null을 넣으면 500이 뜨는 에러 수정 * feat: 로그를 json 형태로 수정 * feat: 로그를 json 인덴트 추가 --- .../haengdong/exception/GlobalExceptionHandler.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java index ec8e4cba0..0cee7cb4c 100644 --- a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java +++ b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java @@ -19,11 +19,11 @@ public class GlobalExceptionHandler { private static final String LOG_FORMAT = """ - { + \n\t{ "RequestURI": "{} {}", - "RequestBody": "{}", + "RequestBody": {}, "ErrorMessage": "{}" - } + \t} """; @ExceptionHandler(AuthenticationException.class) @@ -81,7 +81,7 @@ public ResponseEntity<ErrorResponse> handleException(HttpServletRequest req, Exc private String getRequestBody(HttpServletRequest req) { try (BufferedReader reader = req.getReader()) { - return reader.lines().collect(Collectors.joining(System.lineSeparator())); + return reader.lines().collect(Collectors.joining(System.lineSeparator() + "\t")); } catch (IOException e) { log.error("Failed to read request body", e); return ""; From 90daed52e69a4b033a835f365a5b2c866b2764af Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Tue, 20 Aug 2024 13:10:29 +0900 Subject: [PATCH 152/178] =?UTF-8?q?refactor:=20BillActionDetail=20isFixed?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80=20(#405)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/BillActionDetailService.java | 3 +- .../application/BillActionService.java | 2 +- .../application/MemberActionService.java | 41 +++++++++++++++---- .../BillActionDetailUpdateAppRequest.java | 3 +- .../response/BillActionDetailAppResponse.java | 9 +++- .../domain/action/BillActionDetail.java | 17 +++----- .../BillActionDetailUpdateRequest.java | 7 +++- .../response/BillActionDetailResponse.java | 9 +++- .../application/ActionServiceTest.java | 11 ++--- .../BillActionDetailServiceTest.java | 20 ++++----- .../application/BillActionServiceTest.java | 12 +++--- .../application/MemberActionServiceTest.java | 14 ++++--- .../BillActionDetailControllerDocsTest.java | 15 ++++--- .../domain/action/BillActionTest.java | 9 ++-- .../domain/action/MemberBillReportTest.java | 11 ++--- .../BillActionDetailControllerTest.java | 6 +-- .../haengdong/support/fixture/Fixture.java | 4 ++ 17 files changed, 121 insertions(+), 72 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/BillActionDetailService.java b/server/src/main/java/server/haengdong/application/BillActionDetailService.java index 5d4cf335a..aadddc00e 100644 --- a/server/src/main/java/server/haengdong/application/BillActionDetailService.java +++ b/server/src/main/java/server/haengdong/application/BillActionDetailService.java @@ -27,7 +27,7 @@ public BillActionDetailsAppResponse findBillActionDetails(String token, Long act BillAction billAction = billActionRepository.findByAction_Id(actionId) .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); validateToken(token, billAction); - + List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(billAction); return BillActionDetailsAppResponse.of(billActionDetails); @@ -52,6 +52,7 @@ public void updateBillActionDetails(String token, Long actionId, BillActionDetai .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_DETAIL_NOT_FOUND)); detailToUpdate.updatePrice(updateRequest.price()); + detailToUpdate.updateIsFixed(updateRequest.isFixed()); } } diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java index 95717d825..bf0e9e05c 100644 --- a/server/src/main/java/server/haengdong/application/BillActionService.java +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -57,7 +57,7 @@ private Action createStartAction(Event event) { private void saveBillActionDetails(BillAction billAction, CurrentMembers currentMembers) { long pricePerMember = billAction.getPrice() / currentMembers.size(); currentMembers.getMembers().stream() - .map(memberName -> new BillActionDetail(billAction, memberName, pricePerMember)) + .map(memberName -> new BillActionDetail(billAction, memberName, pricePerMember, false)) .forEach(billActionDetailRepository::save); } diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java index 47d336c60..b5215688a 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionService.java +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -1,6 +1,8 @@ package server.haengdong.application; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -86,26 +88,49 @@ public void deleteMemberAction(String token, Long actionId) { .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_ACTION_NOT_FOUND)); memberActionRepository.deleteAllByMemberNameAndMinSequence(memberAction.getMemberName(), - memberAction.getSequence()); + memberAction.getSequence()); List<BillAction> billActions = billActionRepository.findByEventAndGreaterThanSequence(event, - action.getSequence()); + action.getSequence()); billActions.forEach(billAction -> resetBillAction(event, billAction)); } private void resetBillAction(Event event, BillAction billAction) { List<MemberAction> memberActions = memberActionRepository.findByEventAndSequence(event, - billAction.getSequence()); + billAction.getSequence()); CurrentMembers currentMembers = CurrentMembers.of(memberActions); billActionDetailRepository.deleteAllByBillAction(billAction); if (currentMembers.isNotEmpty()) { - Long eachPrice = billAction.getPrice() / currentMembers.size(); - for (String member : currentMembers.getMembers()) { - BillActionDetail billActionDetail = new BillActionDetail(billAction, member, eachPrice); - billActionDetailRepository.save(billActionDetail); - } + Long price = billAction.getPrice(); + int currentMemberCount = currentMembers.size(); + long eachPrice = price / currentMemberCount; + long remainder = price % currentMemberCount; + List<BillActionDetail> billActionDetails = getBillActionDetails( + billAction, + currentMembers, + eachPrice, + remainder + ); + billActionDetailRepository.saveAll(billActionDetails); } } + + private List<BillActionDetail> getBillActionDetails( + BillAction billAction, + CurrentMembers currentMembers, + long eachPrice, + long remainder + ) { + List<String> members = currentMembers.getMembers().stream().toList(); + List<BillActionDetail> billActionDetails = IntStream.range(0, members.size() - 1) + .mapToObj(index -> new BillActionDetail(billAction, members.get(index), eachPrice, false)) + .collect(Collectors.toList()); + BillActionDetail lastBillActionDetail = new BillActionDetail(billAction, members.get(members.size() - 1), + eachPrice + remainder, false); + billActionDetails.add(lastBillActionDetail); + + return billActionDetails; + } } diff --git a/server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java index a815e4afa..e514aee81 100644 --- a/server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java +++ b/server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java @@ -2,6 +2,7 @@ public record BillActionDetailUpdateAppRequest( String name, - Long price + Long price, + boolean isFixed ) { } diff --git a/server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java b/server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java index 1ddb51671..3efc7ac9d 100644 --- a/server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java +++ b/server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java @@ -4,10 +4,15 @@ public record BillActionDetailAppResponse( String name, - Long price + Long price, + boolean isFixed ) { public static BillActionDetailAppResponse of(BillActionDetail billActionDetail) { - return new BillActionDetailAppResponse(billActionDetail.getMemberName(), billActionDetail.getPrice()); + return new BillActionDetailAppResponse( + billActionDetail.getMemberName(), + billActionDetail.getPrice(), + billActionDetail.isFixed() + ); } } diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java index 06847c2bb..ad13e6ab2 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java @@ -26,26 +26,21 @@ public class BillActionDetail { private Long price; - public BillActionDetail(String memberName, Long price) { - this.memberName = memberName; - this.price = price; - } + private boolean isFixed; - public BillActionDetail(BillAction billAction, String memberName, Long price) { + public BillActionDetail(BillAction billAction, String memberName, Long price, boolean isFixed) { this.billAction = billAction; this.memberName = memberName; this.price = price; + this.isFixed = isFixed; } - public BillActionDetail(Long id, BillAction billAction, String memberName, Long price) { - this.id = id; - this.billAction = billAction; - this.memberName = memberName; + public void updatePrice(Long price) { this.price = price; } - public void updatePrice(Long price) { - this.price = price; + public void updateIsFixed(boolean isFixed) { + this.isFixed = isFixed; } public boolean hasMemberName(String memberName) { diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java index 2988f2ace..21c4bd60f 100644 --- a/server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java @@ -10,9 +10,12 @@ public record BillActionDetailUpdateRequest( String name, @NotNull(message = "지출 금액은 공백일 수 없습니다.") - Long price + Long price, + + @NotNull(message = "지출 금액은 공백일 수 없습니다.") + boolean isFixed ) { public BillActionDetailUpdateAppRequest toAppRequest() { - return new BillActionDetailUpdateAppRequest(this.name, this.price); + return new BillActionDetailUpdateAppRequest(this.name, this.price, this.isFixed); } } diff --git a/server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java b/server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java index 46d56438c..10f71b82e 100644 --- a/server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java +++ b/server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java @@ -4,10 +4,15 @@ public record BillActionDetailResponse( String name, - Long price + Long price, + boolean isFixed ) { public static BillActionDetailResponse of(BillActionDetailAppResponse billActionDetailAppResponse) { - return new BillActionDetailResponse(billActionDetailAppResponse.name(), billActionDetailAppResponse.price()); + return new BillActionDetailResponse( + billActionDetailAppResponse.name(), + billActionDetailAppResponse.price(), + billActionDetailAppResponse.isFixed() + ); } } diff --git a/server/src/test/java/server/haengdong/application/ActionServiceTest.java b/server/src/test/java/server/haengdong/application/ActionServiceTest.java index 389b426df..ee979b278 100644 --- a/server/src/test/java/server/haengdong/application/ActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/ActionServiceTest.java @@ -5,6 +5,7 @@ import static org.assertj.core.api.Assertions.tuple; import static server.haengdong.domain.action.MemberActionStatus.IN; import static server.haengdong.domain.action.MemberActionStatus.OUT; +import static server.haengdong.support.fixture.Fixture.BILL_ACTION; import java.util.List; import org.junit.jupiter.api.DisplayName; @@ -54,15 +55,15 @@ void getMemberBillReports() { ); billActions.get(0).addDetails( List.of( - new BillActionDetail("소하", 10_000L), - new BillActionDetail("감자", 40_000L), - new BillActionDetail("쿠키", 10_000L) + new BillActionDetail(BILL_ACTION, "소하", 10_000L, false), + new BillActionDetail(BILL_ACTION, "감자", 40_000L, true), + new BillActionDetail(BILL_ACTION, "쿠키", 10_000L, false) ) ); billActions.get(1).addDetails( List.of( - new BillActionDetail("소하", 5_000L), - new BillActionDetail("쿠키", 15_000L) + new BillActionDetail(BILL_ACTION, "소하", 5_000L, true), + new BillActionDetail(BILL_ACTION, "쿠키", 15_000L, true) ) ); memberActionRepository.saveAll(memberActions); diff --git a/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java index 3e7aee56e..7074ce846 100644 --- a/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java +++ b/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java @@ -44,8 +44,8 @@ void findBillActionDetailsTest() { Action action = new Action(event1, 1L); BillAction billAction = new BillAction(action, "뽕족", 10000L); billActionRepository.save(billAction); - BillActionDetail billActionDetail1 = new BillActionDetail(1L, billAction, "토다리", 6000L); - BillActionDetail billActionDetail2 = new BillActionDetail(2L, billAction, "쿠키", 4000L); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "토다리", 6000L, true); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "쿠키", 4000L, true); billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); BillActionDetailsAppResponse response = billActionDetailService.findBillActionDetails( @@ -67,13 +67,13 @@ void updateBillActionDetailsTest1() { Action action = new Action(event1, 1L); BillAction billAction = new BillAction(action, "뽕족", 10000L); billActionRepository.save(billAction); - BillActionDetail billActionDetail1 = new BillActionDetail(1L, billAction, "토다리", 5000L); - BillActionDetail billActionDetail2 = new BillActionDetail(2L, billAction, "쿠키", 5000L); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "토다리", 5000L, false); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "쿠키", 5000L, false); billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); BillActionDetailsUpdateAppRequest request = new BillActionDetailsUpdateAppRequest(List.of( - new BillActionDetailUpdateAppRequest("토다리", 3000L), - new BillActionDetailUpdateAppRequest("쿠키", 4000L) + new BillActionDetailUpdateAppRequest("토다리", 3000L, true), + new BillActionDetailUpdateAppRequest("쿠키", 4000L, true) )); assertThatCode( () -> billActionDetailService.updateBillActionDetails(event1.getToken(), action.getId(), request)) @@ -89,13 +89,13 @@ void updateBillActionDetailsTest2() { Action action = new Action(event1, 1L); BillAction billAction = new BillAction(action, "뽕족", 10000L); billActionRepository.save(billAction); - BillActionDetail billActionDetail1 = new BillActionDetail(1L, billAction, "토다리", 5000L); - BillActionDetail billActionDetail2 = new BillActionDetail(2L, billAction, "쿠키", 5000L); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "토다리", 5000L, false); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "쿠키", 5000L, false); billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); BillActionDetailsUpdateAppRequest request = new BillActionDetailsUpdateAppRequest(List.of( - new BillActionDetailUpdateAppRequest("토다리", 3000L), - new BillActionDetailUpdateAppRequest("쿠키", 7000L) + new BillActionDetailUpdateAppRequest("토다리", 3000L, true), + new BillActionDetailUpdateAppRequest("쿠키", 7000L, true) )); billActionDetailService.updateBillActionDetails(event1.getToken(), action.getId(), request); diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java index c0e588288..39e52f80c 100644 --- a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java @@ -161,10 +161,10 @@ void updateBillAction2() { Event savedEvent = eventRepository.save(event); Action action = Action.createFirst(savedEvent); BillAction billAction = new BillAction(action, "뽕족", 10_000L); - BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "감자", 3000L); - BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "고구마", 2000L); - BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "당근", 3000L); - BillActionDetail billActionDetail4 = new BillActionDetail(billAction, "양파", 2000L); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "감자", 3000L, true); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "고구마", 2000L, true); + BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "당근", 3000L, true); + BillActionDetail billActionDetail4 = new BillActionDetail(billAction, "양파", 2000L, true); billAction.addDetails(List.of(billActionDetail1, billActionDetail2, billActionDetail3, billActionDetail4)); BillAction savedBillAction = billActionRepository.save(billAction); @@ -208,8 +208,8 @@ void deleteBillActionTest1() { MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "백호", MemberActionStatus.IN, 1L); MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "망쵸", MemberActionStatus.IN, 2L); BillAction billAction = new BillAction(new Action(event, 3L), "커피", 50_900L); - BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "백호", 25_450L); - BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "망쵸", 25_450L); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "백호", 25_450L, false); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "망쵸", 25_450L, false); memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); billActionRepository.save(billAction); billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java index 06368a9fb..b6d29444c 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java @@ -146,10 +146,12 @@ void deleteMember1() { ); BillAction billAction = new BillAction(new Action(event, 6L), "뽕족", 100_000L); billActionRepository.save(billAction); - BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "쿠키", 40_000L); - BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "웨디", 30_000L); - BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "감자", 30_000L); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "쿠키", 40_000L, true); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "웨디", 30_000L, false); + BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "감자", 30_000L, false); billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3)); + List<BillActionDetail> allByBillAction = billActionDetailRepository.findAllByBillAction(billAction); + System.out.println("allByBillAction = " + allByBillAction.isEmpty()); memberActionService.deleteMember(event.getToken(), "쿠키"); @@ -220,9 +222,9 @@ void deleteMemberAction1() { ); BillAction billAction = new BillAction(new Action(event, 6L), "뽕족", 100_000L); billActionRepository.save(billAction); - BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "쿠키", 40_000L); - BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "웨디", 30_000L); - BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "감자", 30_000L); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "쿠키", 40_000L, true); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "웨디", 30_000L, false); + BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "감자", 30_000L, false); billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3)); memberActionService.deleteMemberAction(event.getToken(), targetAction.getId()); diff --git a/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java index 3116cba5e..f492195f3 100644 --- a/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java @@ -47,7 +47,7 @@ protected Object initController() { @Test void findBillActionDetailsTest() throws Exception { BillActionDetailsAppResponse appResponse = new BillActionDetailsAppResponse( - List.of(new BillActionDetailAppResponse("토다리", 1000L))); + List.of(new BillActionDetailAppResponse("토다리", 1000L, false))); given(billActionDetailService.findBillActionDetails(anyString(), anyLong())) .willReturn(appResponse); @@ -58,6 +58,7 @@ void findBillActionDetailsTest() throws Exception { .andExpect(jsonPath("$.members").isArray()) .andExpect(jsonPath("$.members[0].name").value("토다리")) .andExpect(jsonPath("$.members[0].price").value(1000L)) + .andExpect(jsonPath("$.members[0].isFixed").value(false)) .andDo( document("findBillActionDetailsTest", preprocessRequest(prettyPrint()), @@ -73,7 +74,9 @@ void findBillActionDetailsTest() throws Exception { fieldWithPath("members[0].name").type(JsonFieldType.STRING) .description("참여자 이름"), fieldWithPath("members[0].price").type(JsonFieldType.NUMBER) - .description("참여자 정산 금액") + .description("참여자 정산 금액"), + fieldWithPath("members[0].isFixed").type(JsonFieldType.BOOLEAN) + .description("참여자 정산 금액 수정 여부") ) ) ); @@ -83,8 +86,8 @@ void findBillActionDetailsTest() throws Exception { @Test void updateBillActionDetailsTest() throws Exception { List<BillActionDetailUpdateRequest> billActionDetailUpdateRequests = List.of( - new BillActionDetailUpdateRequest("소하", 10000L), - new BillActionDetailUpdateRequest("웨디", 20000L) + new BillActionDetailUpdateRequest("소하", 10000L, true), + new BillActionDetailUpdateRequest("웨디", 20000L, true) ); BillActionDetailsUpdateRequest request = new BillActionDetailsUpdateRequest( billActionDetailUpdateRequests); @@ -114,7 +117,9 @@ void updateBillActionDetailsTest() throws Exception { fieldWithPath("members[0].name").type(JsonFieldType.STRING) .description("참여자 이름"), fieldWithPath("members[0].price").type(JsonFieldType.NUMBER) - .description("참여자 정산 금액") + .description("참여자 정산 금액"), + fieldWithPath("members[0].isFixed").type(JsonFieldType.BOOLEAN) + .description("참여자 정산 금액 수정 여부") ) ) ); diff --git a/server/src/test/java/server/haengdong/domain/action/BillActionTest.java b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java index f95558606..ba1ab36f2 100644 --- a/server/src/test/java/server/haengdong/domain/action/BillActionTest.java +++ b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertAll; +import static server.haengdong.support.fixture.Fixture.BILL_ACTION; import static server.haengdong.support.fixture.Fixture.EVENT1; import java.util.List; @@ -64,8 +65,8 @@ void isFixed1() { BillAction fixedBillAction = new BillAction(new Action(EVENT1, 1L), "인생네컷", 2_000L); List<BillActionDetail> unfixedBillActionDetails = List.of( - new BillActionDetail("감자", 1_000L), - new BillActionDetail("고구마", 1_000L) + new BillActionDetail(BILL_ACTION, "감자", 1_000L, false), + new BillActionDetail(BILL_ACTION, "고구마", 1_000L, false) ); fixedBillAction.addDetails(unfixedBillActionDetails); @@ -78,8 +79,8 @@ void isFixed2() { BillAction fixedBillAction = new BillAction(new Action(EVENT1, 1L), "인생네컷", 5_000L); List<BillActionDetail> unfixedBillActionDetails = List.of( - new BillActionDetail("감자", 4_000L), - new BillActionDetail("고구마", 1_000L) + new BillActionDetail(BILL_ACTION, "감자", 4_000L, true), + new BillActionDetail(BILL_ACTION, "고구마", 1_000L, true) ); fixedBillAction.addDetails(unfixedBillActionDetails); diff --git a/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java b/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java index 12451435b..02070a537 100644 --- a/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java +++ b/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static server.haengdong.domain.action.MemberActionStatus.IN; import static server.haengdong.domain.action.MemberActionStatus.OUT; +import static server.haengdong.support.fixture.Fixture.BILL_ACTION; import java.util.List; import java.util.Map; @@ -23,15 +24,15 @@ void createByActions() { ); billActions.get(0).addDetails( List.of( - new BillActionDetail("소하", 10_000L), - new BillActionDetail("감자", 40_000L), - new BillActionDetail("쿠키", 10_000L) + new BillActionDetail(BILL_ACTION, "소하", 10_000L, false), + new BillActionDetail(BILL_ACTION, "감자", 40_000L, true), + new BillActionDetail(BILL_ACTION, "쿠키", 10_000L, false) ) ); billActions.get(1).addDetails( List.of( - new BillActionDetail("소하", 5_000L), - new BillActionDetail("쿠키", 15_000L) + new BillActionDetail(BILL_ACTION, "소하", 5_000L, true), + new BillActionDetail(BILL_ACTION, "쿠키", 15_000L, true) ) ); List<MemberAction> memberActions = List.of( diff --git a/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java index f098153d4..6b595ee27 100644 --- a/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java @@ -24,7 +24,7 @@ class BillActionDetailControllerTest extends ControllerTestSupport { @Test void findBillActionDetails() throws Exception { BillActionDetailsAppResponse appResponse = new BillActionDetailsAppResponse( - List.of(new BillActionDetailAppResponse("토다리", 1000L))); + List.of(new BillActionDetailAppResponse("토다리", 1000L, false))); given(billActionDetailService.findBillActionDetails(anyString(), anyLong())) .willReturn(appResponse); @@ -39,8 +39,8 @@ void findBillActionDetails() throws Exception { @Test void updateBillActionDetailsTest() throws Exception { List<BillActionDetailUpdateRequest> billActionDetailUpdateRequests = List.of( - new BillActionDetailUpdateRequest("소하", 10000L), - new BillActionDetailUpdateRequest("웨디", 20000L) + new BillActionDetailUpdateRequest("소하", 10000L, true), + new BillActionDetailUpdateRequest("웨디", 20000L, true) ); BillActionDetailsUpdateRequest request = new BillActionDetailsUpdateRequest( billActionDetailUpdateRequests); diff --git a/server/src/test/java/server/haengdong/support/fixture/Fixture.java b/server/src/test/java/server/haengdong/support/fixture/Fixture.java index fea2bd69a..6844915d9 100644 --- a/server/src/test/java/server/haengdong/support/fixture/Fixture.java +++ b/server/src/test/java/server/haengdong/support/fixture/Fixture.java @@ -1,6 +1,8 @@ package server.haengdong.support.fixture; import jakarta.servlet.http.Cookie; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; import server.haengdong.domain.event.Event; public class Fixture { @@ -8,4 +10,6 @@ public class Fixture { public static final Event EVENT1 = new Event("쿠키", "1234", "TOKEN1"); public static final Event EVENT2 = new Event("웨디", "1234", "TOKEN2"); public static final Cookie EVENT_COOKIE = new Cookie("eventToken", "토큰토큰"); + public static final Action ACTION = new Action(EVENT1, 1L); + public static final BillAction BILL_ACTION = new BillAction(ACTION, "뽕족", 30_000L); } From 597493912df646d553ce5b190d01c69730c94da2 Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Tue, 20 Aug 2024 21:54:25 +0900 Subject: [PATCH 153/178] =?UTF-8?q?fix:=20=EB=A1=9C=EA=B9=85=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=20=ED=9B=84=20=EC=98=88=EC=99=B8=20=EC=9D=91=EB=8B=B5?= =?UTF-8?q?=20=EB=B6=88=EA=B0=80=20=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=20(#413)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/RequestServletFilter.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 server/src/main/java/server/haengdong/config/RequestServletFilter.java diff --git a/server/src/main/java/server/haengdong/config/RequestServletFilter.java b/server/src/main/java/server/haengdong/config/RequestServletFilter.java new file mode 100644 index 000000000..b1afdb6f8 --- /dev/null +++ b/server/src/main/java/server/haengdong/config/RequestServletFilter.java @@ -0,0 +1,23 @@ +package server.haengdong.config; + +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import java.io.IOException; +import org.springframework.stereotype.Component; +import org.springframework.web.util.ContentCachingRequestWrapper; + +@Component +public class RequestServletFilter implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper((HttpServletRequest) request); + + chain.doFilter(wrappedRequest, response); + } +} From 39efc6903d72f4809bfabcd893801437c053b4f2 Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Wed, 21 Aug 2024 10:27:38 +0900 Subject: [PATCH 154/178] =?UTF-8?q?feat:=20=EC=95=A1=EC=85=98=20=EC=9D=B4?= =?UTF-8?q?=EB=A0=A5=20=EC=A1=B0=ED=9A=8C=20stepName=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20(#420)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../haengdong/presentation/response/StepResponse.java | 4 +++- .../haengdong/presentation/response/StepsResponse.java | 6 +++++- .../server/haengdong/docs/EventControllerDocsTest.java | 5 +++++ .../presentation/response/StepsResponseTest.java | 10 +++++----- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/server/src/main/java/server/haengdong/presentation/response/StepResponse.java b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java index c3e854f4e..55dd62c58 100644 --- a/server/src/main/java/server/haengdong/presentation/response/StepResponse.java +++ b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java @@ -5,12 +5,14 @@ import server.haengdong.application.response.ActionAppResponse; public record StepResponse( + String stepName, String type, List<String> members, List<ActionResponse> actions ) { - public static StepResponse of(List<String> members, List<ActionAppResponse> actions) { + public static StepResponse of(String stepName, List<String> members, List<ActionAppResponse> actions) { return new StepResponse( + stepName, actions.get(0).actionTypeName(), new ArrayList<>(members), toActionsResponse(actions) diff --git a/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java b/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java index ac147387d..5f7573d67 100644 --- a/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java +++ b/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java @@ -12,9 +12,13 @@ public static StepsResponse of(List<ActionAppResponse> actions) { List<String> currentMembers = new ArrayList<>(); List<List<ActionAppResponse>> groups = createGroups(actions); + int billStepCount = 0; for (List<ActionAppResponse> group : groups) { changeCurrentMembers(group, currentMembers); - StepResponse stepResponse = StepResponse.of(currentMembers, group); + if (group.get(0).actionType() == ActionType.BILL) { + billStepCount++; + } + StepResponse stepResponse = StepResponse.of(billStepCount + "차", currentMembers, group); steps.add(stepResponse); } return new StepsResponse(steps); diff --git a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java index bc7f15d6e..88de2a3a6 100644 --- a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java @@ -237,6 +237,7 @@ void findActions() throws Exception { .andDo(print()) .andExpect(status().isOk()) .andExpect(jsonPath("$.steps[0].type").value(equalTo("IN"))) + .andExpect(jsonPath("$.steps[0].stepName").value(equalTo("0차"))) .andExpect(jsonPath("$.steps[0].members[0]").value(equalTo("망쵸"))) .andExpect(jsonPath("$.steps[0].actions[0].actionId").value(equalTo(1))) .andExpect(jsonPath("$.steps[0].actions[0].name").value(equalTo("망쵸"))) @@ -244,6 +245,7 @@ void findActions() throws Exception { .andExpect(jsonPath("$.steps[0].actions[0].sequence").value(equalTo(1))) .andExpect(jsonPath("$.steps[1].type").value(equalTo("BILL"))) + .andExpect(jsonPath("$.steps[1].stepName").value(equalTo("1차"))) .andExpect(jsonPath("$.steps[1].members[0]").value(equalTo("망쵸"))) .andExpect(jsonPath("$.steps[1].actions[0].actionId").value(equalTo(2))) .andExpect(jsonPath("$.steps[1].actions[0].name").value(equalTo("족발"))) @@ -256,6 +258,7 @@ void findActions() throws Exception { .andExpect(jsonPath("$.steps[1].actions[1].sequence").value(equalTo(3))) .andExpect(jsonPath("$.steps[2].type").value(equalTo("OUT"))) + .andExpect(jsonPath("$.steps[2].stepName").value(equalTo("1차"))) .andExpect(jsonPath("$.steps[2].actions[0].actionId").value(equalTo(4))) .andExpect(jsonPath("$.steps[2].actions[0].name").value(equalTo("망쵸"))) .andExpect(jsonPath("$.steps[2].actions[0].price").value(equalTo(null))) @@ -269,6 +272,8 @@ void findActions() throws Exception { parameterWithName("eventId").description("행사 ID") ), responseFields( + fieldWithPath("steps[].stepName").type(JsonFieldType.STRING) + .description("스탭 이름"), fieldWithPath("steps[].type").type(JsonFieldType.STRING) .description("액션 유형 [BILL, IN, OUT]"), fieldWithPath("steps[].members").type(JsonFieldType.ARRAY) diff --git a/server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java b/server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java index f8fdb6e7d..051fcae0f 100644 --- a/server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java +++ b/server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java @@ -30,23 +30,23 @@ void of() { StepsResponse expected = new StepsResponse( List.of( - new StepResponse("IN", List.of("망쵸", "백호"), List.of( + new StepResponse("0차", "IN", List.of("망쵸", "백호"), List.of( new ActionResponse(1L, "망쵸", null, 1L), new ActionResponse(2L, "백호", null, 2L) )), - new StepResponse("BILL", List.of("망쵸", "백호"), List.of( + new StepResponse("1차", "BILL", List.of("망쵸", "백호"), List.of( new ActionResponse(3L, "감자탕", 10_000L, 3L), new ActionResponse(4L, "인생네컷", 10_000L, 4L) )), - new StepResponse("IN", List.of("망쵸", "백호", "소하", "웨디"), List.of( + new StepResponse("1차", "IN", List.of("망쵸", "백호", "소하", "웨디"), List.of( new ActionResponse(5L, "소하", null, 5L), new ActionResponse(6L, "웨디", null, 6L) )), - new StepResponse("OUT", List.of("소하", "웨디"), List.of( + new StepResponse("1차", "OUT", List.of("소하", "웨디"), List.of( new ActionResponse(7L, "망쵸", null, 7L), new ActionResponse(8L, "백호", null, 8L) )), - new StepResponse("BILL", List.of("소하", "웨디"), List.of( + new StepResponse("2차", "BILL", List.of("소하", "웨디"), List.of( new ActionResponse(9L, "노래방", 20_000L, 9L) )) ) From be175d27b9bee6e0fb2ab3689b3b6f70175ba452 Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Wed, 21 Aug 2024 13:59:03 +0900 Subject: [PATCH 155/178] =?UTF-8?q?feat:=20=EC=9D=B4=EC=8A=88,=20PR=20?= =?UTF-8?q?=ED=85=9C=ED=94=8C=EB=A6=BF=20=EC=B6=94=EA=B0=80=20(#160)=20(#4?= =?UTF-8?q?26)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From a4326560483ce2c94572941fa506f9bd16855a74 Mon Sep 17 00:00:00 2001 From: Arachneee <jhg2819@naver.com> Date: Wed, 21 Aug 2024 16:44:55 +0900 Subject: [PATCH 156/178] =?UTF-8?q?fix:=20BillAction=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=EC=8B=9C=20BillDetail=20=EC=B4=88=EA=B8=B0=ED=99=94=20?= =?UTF-8?q?=EC=95=88=EB=90=98=EB=8A=94=20=EB=B2=84=EA=B7=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/server/haengdong/application/BillActionService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java index bf0e9e05c..aecd5e38a 100644 --- a/server/src/main/java/server/haengdong/application/BillActionService.java +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -74,12 +74,13 @@ public void updateBillAction(String token, Long actionId, BillActionUpdateAppReq } private void resetBillActionDetail(BillAction billAction, Long updatePrice) { - if (billAction.getPrice() != updatePrice) { + if (billAction.getPrice().equals(updatePrice)) { List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(billAction); int memberCount = billActionDetails.size(); if (memberCount != 0) { Long eachPrice = updatePrice / memberCount; billActionDetails.forEach(billActionDetail -> billActionDetail.updatePrice(eachPrice)); + billActionDetails.forEach(billActionDetail -> billActionDetail.updateIsFixed(false)); } } } From de5e7ce3cdb8bbd7d0b273b7f4d7530a28d716d3 Mon Sep 17 00:00:00 2001 From: Arachneee <jhg2819@naver.com> Date: Wed, 21 Aug 2024 16:44:55 +0900 Subject: [PATCH 157/178] =?UTF-8?q?fix:=20BillAction=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=EC=8B=9C=20BillDetail=20=EC=B4=88=EA=B8=B0=ED=99=94=20?= =?UTF-8?q?=EC=95=88=EB=90=98=EB=8A=94=20=EB=B2=84=EA=B7=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/server/haengdong/application/BillActionService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java index bf0e9e05c..c29720a98 100644 --- a/server/src/main/java/server/haengdong/application/BillActionService.java +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -74,12 +74,13 @@ public void updateBillAction(String token, Long actionId, BillActionUpdateAppReq } private void resetBillActionDetail(BillAction billAction, Long updatePrice) { - if (billAction.getPrice() != updatePrice) { + if (!billAction.getPrice().equals(updatePrice)) { List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(billAction); int memberCount = billActionDetails.size(); if (memberCount != 0) { Long eachPrice = updatePrice / memberCount; billActionDetails.forEach(billActionDetail -> billActionDetail.updatePrice(eachPrice)); + billActionDetails.forEach(billActionDetail -> billActionDetail.updateIsFixed(false)); } } } From 084fb5f71e79596272b1dd6dd2fedb14a61a6b9a Mon Sep 17 00:00:00 2001 From: Arachneee <jhg2819@naver.com> Date: Wed, 21 Aug 2024 16:51:24 +0900 Subject: [PATCH 158/178] =?UTF-8?q?fix:=20BillAction=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=EC=8B=9C=20BillDetail=20=EC=B4=88=EA=B8=B0=ED=99=94=20?= =?UTF-8?q?=EC=95=88=EB=90=98=EB=8A=94=20=EB=B2=84=EA=B7=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/haengdong/application/BillActionService.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java index c29720a98..55a14d4d0 100644 --- a/server/src/main/java/server/haengdong/application/BillActionService.java +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -79,8 +79,11 @@ private void resetBillActionDetail(BillAction billAction, Long updatePrice) { int memberCount = billActionDetails.size(); if (memberCount != 0) { Long eachPrice = updatePrice / memberCount; - billActionDetails.forEach(billActionDetail -> billActionDetail.updatePrice(eachPrice)); - billActionDetails.forEach(billActionDetail -> billActionDetail.updateIsFixed(false)); + billActionDetails.forEach(billActionDetail -> { + billActionDetail.updatePrice(eachPrice); + billActionDetail.updateIsFixed(false); + } + ); } } } From 44ff15d69f4345b419e29751f5ddfa2ad8d5a4c4 Mon Sep 17 00:00:00 2001 From: Arachneee <jhg2819@naver.com> Date: Wed, 21 Aug 2024 17:39:34 +0900 Subject: [PATCH 159/178] =?UTF-8?q?docs:=20pr=20issue=20close=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pr-issue-close.yml | 36 ---------------------------- 1 file changed, 36 deletions(-) delete mode 100644 .github/workflows/pr-issue-close.yml diff --git a/.github/workflows/pr-issue-close.yml b/.github/workflows/pr-issue-close.yml deleted file mode 100644 index 91e43e206..000000000 --- a/.github/workflows/pr-issue-close.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Close Issue on PR Merge - -on: - pull_request: - types: [closed] - -jobs: - close-issue: - if: github.event.pull_request.merged == true - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Extract issue number from PR body - id: extract_issue - run: | - # Fetch PR body - PR_BODY=$(curl -s -H "Authorization: token ${{ secrets.CONFIG_SUBMODULE_TOKEN }}" \ - "https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}" \ - | jq -r '.body') - - # Extract issue number from PR body using regex (customize if needed) - ISSUE_NUMBER=$(echo "$PR_BODY" | grep -oP '#\d+' | head -1 | sed 's/#//') - - echo "ISSUE_NUMBER=$ISSUE_NUMBER" >> $GITHUB_ENV - - - name: Close associated issue - if: env.ISSUE_NUMBER != '' - run: | - echo "Closing issue #${{ env.ISSUE_NUMBER }}" - curl -s -X PATCH -H "Authorization: token ${{ secrets.CONFIG_SUBMODULE_TOKEN }}" \ - -H "Accept: application/vnd.github.v3+json" \ - -d '{"state": "closed"}' \ - "https://api.github.com/repos/${{ github.repository }}/issues/${{ env.ISSUE_NUMBER }}" From 817c965ff7e8f053aff92d4d91673b0dada5ef52 Mon Sep 17 00:00:00 2001 From: JUHA <84626225+khabh@users.noreply.github.com> Date: Wed, 21 Aug 2024 23:29:29 +0900 Subject: [PATCH 160/178] =?UTF-8?q?feat:=20=ED=96=89=EC=82=AC=20=EB=B9=84?= =?UTF-8?q?=EB=B0=80=EB=B2=88=ED=98=B8=20=EC=95=94=ED=98=B8=ED=99=94=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(#429)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 행사 비밀번호 암호화 추가 * refactor: 비밀번호 암호화 로직 수정 * fix: MessageDigest를 싱글톤으로 관리하지 않도록 수정 --------- Co-authored-by: 3juhwan <13selfesteem91@naver.com> --- .../haengdong/application/EventService.java | 2 +- .../server/haengdong/domain/event/Event.java | 25 ++++----- .../haengdong/domain/event/Password.java | 52 +++++++++++++++++++ .../exception/HaengdongErrorCode.java | 3 +- .../haengdong/domain/event/EventTest.java | 20 +++++++ .../haengdong/domain/event/PasswordTest.java | 19 +++++++ 6 files changed, 103 insertions(+), 18 deletions(-) create mode 100644 server/src/main/java/server/haengdong/domain/event/Password.java create mode 100644 server/src/test/java/server/haengdong/domain/event/PasswordTest.java diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java index 3d2400372..834c0e10a 100644 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -153,7 +153,7 @@ private void updateMemberName(Event event, String beforeName, String afterName) public void validatePassword(EventLoginAppRequest request) throws HaengdongException { Event event = getEvent(request.token()); - if (event.isNotSamePassword(request.password())) { + if (event.isPasswordMismatch(request.password())) { throw new AuthenticationException(HaengdongErrorCode.PASSWORD_INVALID); } } diff --git a/server/src/main/java/server/haengdong/domain/event/Event.java b/server/src/main/java/server/haengdong/domain/event/Event.java index cd576a967..bb5d53dbc 100644 --- a/server/src/main/java/server/haengdong/domain/event/Event.java +++ b/server/src/main/java/server/haengdong/domain/event/Event.java @@ -1,11 +1,12 @@ package server.haengdong.domain.event; +import jakarta.persistence.AttributeOverride; +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -19,9 +20,7 @@ public class Event { public static final int MIN_NAME_LENGTH = 1; public static final int MAX_NAME_LENGTH = 20; - public static final int PASSWORD_LENGTH = 4; private static final String SPACES = " "; - private static final Pattern PASSWORD_PATTERN = Pattern.compile(String.format("^\\d{%d}$", PASSWORD_LENGTH)); @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -29,15 +28,16 @@ public class Event { private String name; - private String password; + @Embedded + @AttributeOverride(name = "value", column = @Column(name = "password")) + private Password password; private String token; public Event(String name, String password, String token) { validateName(name); - validatePassword(password); this.name = name; - this.password = password; + this.password = new Password(password); this.token = token; } @@ -56,13 +56,6 @@ private void validateName(String name) { } } - private void validatePassword(String password) { - Matcher matcher = PASSWORD_PATTERN.matcher(password); - if (!matcher.matches()) { - throw new HaengdongException(HaengdongErrorCode.EVENT_PASSWORD_FORMAT_INVALID, "비밀번호는 4자리 숫자만 가능합니다."); - } - } - private boolean isBlankContinuous(String name) { return name.contains(SPACES); } @@ -71,7 +64,7 @@ public boolean isTokenMismatch(String token) { return !this.token.equals(token); } - public boolean isNotSamePassword(String password) { - return !this.password.equals(password); + public boolean isPasswordMismatch(String rawPassword) { + return !password.matches(rawPassword); } } diff --git a/server/src/main/java/server/haengdong/domain/event/Password.java b/server/src/main/java/server/haengdong/domain/event/Password.java new file mode 100644 index 000000000..375849dbf --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/Password.java @@ -0,0 +1,52 @@ +package server.haengdong.domain.event; + +import jakarta.persistence.Embeddable; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter +@Embeddable +public class Password { + + public static final int PASSWORD_LENGTH = 4; + private static final Pattern PASSWORD_PATTERN = Pattern.compile(String.format("^\\d{%d}$", PASSWORD_LENGTH)); + private static final String HASH_ALGORITHM = "SHA-256"; + + private String value; + + public Password(String password) { + validatePassword(password); + this.value = encode(password); + } + + private void validatePassword(String password) { + Matcher matcher = PASSWORD_PATTERN.matcher(password); + if (!matcher.matches()) { + throw new HaengdongException(HaengdongErrorCode.EVENT_PASSWORD_FORMAT_INVALID); + } + } + + private String encode(String rawPassword) { + try { + MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM); + byte[] hashedPassword = digest.digest(rawPassword.getBytes()); + return Base64.getEncoder().encodeToString(hashedPassword); + } catch (NoSuchAlgorithmException e) { + throw new IllegalArgumentException("해시 알고리즘이 존재하지 않습니다."); + } + } + + public boolean matches(String rawPassword) { + String hashedPassword = encode(rawPassword); + return value.equals(hashedPassword); + } +} diff --git a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java index ff61d4898..475d16c11 100644 --- a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java +++ b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java @@ -4,6 +4,7 @@ import server.haengdong.domain.action.BillAction; import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.Password; @Getter public enum HaengdongErrorCode { @@ -15,7 +16,7 @@ public enum HaengdongErrorCode { Event.MIN_NAME_LENGTH, Event.MAX_NAME_LENGTH)), EVENT_NAME_CONSECUTIVE_SPACES("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s"), - EVENT_PASSWORD_FORMAT_INVALID(String.format("비밀번호는 %d자리 숫자만 가능합니다.", Event.PASSWORD_LENGTH)), + EVENT_PASSWORD_FORMAT_INVALID(String.format("비밀번호는 %d자리 숫자만 가능합니다.", Password.PASSWORD_LENGTH)), ACTION_NOT_FOUND("존재하지 않는 액션입니다."), diff --git a/server/src/test/java/server/haengdong/domain/event/EventTest.java b/server/src/test/java/server/haengdong/domain/event/EventTest.java index a7dba49d9..12c0c0569 100644 --- a/server/src/test/java/server/haengdong/domain/event/EventTest.java +++ b/server/src/test/java/server/haengdong/domain/event/EventTest.java @@ -1,8 +1,10 @@ package server.haengdong.domain.event; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import server.haengdong.exception.HaengdongException; @@ -42,4 +44,22 @@ void validatePassword(String password) { assertThatCode(() -> new Event("이름", password, "TEST_TOKEN")) .isInstanceOf(HaengdongException.class); } + + @DisplayName("비밀번호가 다른지 검증한다.") + @Test + void isNotSamePassword() { + String rawPassword = "1234"; + Event event = new Event("이름", rawPassword, "TEST_TOKEN"); + + assertThat(event.isPasswordMismatch(rawPassword)).isFalse(); + } + + @DisplayName("비밀번호가 다른지 검증한다.") + @Test + void isNotSamePassword1() { + String rawPassword = "1234"; + Event event = new Event("이름", "5678", "TEST_TOKEN"); + + assertThat(event.isPasswordMismatch(rawPassword)).isTrue(); + } } diff --git a/server/src/test/java/server/haengdong/domain/event/PasswordTest.java b/server/src/test/java/server/haengdong/domain/event/PasswordTest.java new file mode 100644 index 000000000..c504d3aa2 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/event/PasswordTest.java @@ -0,0 +1,19 @@ +package server.haengdong.domain.event; + +import static org.assertj.core.api.Assertions.assertThatCode; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import server.haengdong.exception.HaengdongException; + +class PasswordTest { + + @DisplayName("비밀번호는 4자리 숫자 입니다.") + @ParameterizedTest + @ValueSource(strings = {"1", "12", "123", "12345", "adgd"}) + void validatePassword(String rawPassword) { + assertThatCode(() -> new Password(rawPassword)) + .isInstanceOf(HaengdongException.class); + } +} From 63e5be4cf3bd7ef0c1322fa73267a39a362e71c0 Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Thu, 22 Aug 2024 16:24:58 +0900 Subject: [PATCH 161/178] =?UTF-8?q?fix:=20BillActionDetail=20=EC=B4=88?= =?UTF-8?q?=EA=B8=B0=ED=99=94=EC=8B=9C=20totalPrice=EC=99=80=20=EC=A0=95?= =?UTF-8?q?=ED=95=A9=EC=84=B1=20=EC=95=88=EB=A7=9E=EB=8A=94=20=EB=B2=84?= =?UTF-8?q?=EA=B7=B8=20=EC=88=98=EC=A0=95=20=20(#460)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: BillActionDetail 초기화시 totalPrice와 정합성 안맞는 버그 수정 * refactor: BillActionDetail 초기화 로직 BillAction으로 위임 * style: 메소드 이름 수정 * refactor: BillActionDetail 계산 공통 로직 메소드 분리 * fix: price 분배 로직 버그 수정 * style: 미사용 필드 제거 --------- Co-authored-by: Arachneee <jhg2819@naver.com> --- .../application/BillActionDetailService.java | 7 +- .../application/BillActionService.java | 43 ++-------- .../application/MemberActionService.java | 38 +-------- .../request/BillActionAppRequest.java | 5 +- .../haengdong/domain/action/BillAction.java | 84 +++++++++++++------ .../action/BillActionDetailRepository.java | 5 -- 6 files changed, 72 insertions(+), 110 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/BillActionDetailService.java b/server/src/main/java/server/haengdong/application/BillActionDetailService.java index aadddc00e..55d39aac0 100644 --- a/server/src/main/java/server/haengdong/application/BillActionDetailService.java +++ b/server/src/main/java/server/haengdong/application/BillActionDetailService.java @@ -9,7 +9,6 @@ import server.haengdong.application.response.BillActionDetailsAppResponse; import server.haengdong.domain.action.BillAction; import server.haengdong.domain.action.BillActionDetail; -import server.haengdong.domain.action.BillActionDetailRepository; import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.event.Event; import server.haengdong.exception.HaengdongErrorCode; @@ -20,7 +19,6 @@ @Service public class BillActionDetailService { - private final BillActionDetailRepository billActionDetailRepository; private final BillActionRepository billActionRepository; public BillActionDetailsAppResponse findBillActionDetails(String token, Long actionId) { @@ -28,8 +26,7 @@ public BillActionDetailsAppResponse findBillActionDetails(String token, Long act .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); validateToken(token, billAction); - List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(billAction); - + List<BillActionDetail> billActionDetails = billAction.getBillActionDetails(); return BillActionDetailsAppResponse.of(billActionDetails); } @@ -43,7 +40,7 @@ public void updateBillActionDetails(String token, Long actionId, BillActionDetai validateToken(token, billAction); validateTotalPrice(billActionDetailUpdateAppRequests, billAction); - List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(billAction); + List<BillActionDetail> billActionDetails = billAction.getBillActionDetails(); for (BillActionDetailUpdateAppRequest updateRequest : billActionDetailUpdateAppRequests) { BillActionDetail detailToUpdate = billActionDetails.stream() diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java index 55a14d4d0..dae36a2e7 100644 --- a/server/src/main/java/server/haengdong/application/BillActionService.java +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -9,8 +9,6 @@ import server.haengdong.domain.action.Action; import server.haengdong.domain.action.ActionRepository; import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.BillActionDetail; -import server.haengdong.domain.action.BillActionDetailRepository; import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.action.CurrentMembers; import server.haengdong.domain.action.MemberAction; @@ -26,7 +24,6 @@ public class BillActionService { private final BillActionRepository billActionRepository; - private final BillActionDetailRepository billActionDetailRepository; private final MemberActionRepository memberActionRepository; private final ActionRepository actionRepository; private final EventRepository eventRepository; @@ -39,12 +36,9 @@ public void saveAllBillAction(String eventToken, List<BillActionAppRequest> requ CurrentMembers currentMembers = CurrentMembers.of(findMemberActions); for (BillActionAppRequest request : requests) { - BillAction billAction = request.toBillAction(action); + BillAction billAction = request.toBillAction(action, currentMembers); billActionRepository.save(billAction); action = action.next(); - if (currentMembers.isNotEmpty()) { - saveBillActionDetails(billAction, currentMembers); - } } } @@ -54,13 +48,6 @@ private Action createStartAction(Event event) { .orElse(Action.createFirst(event)); } - private void saveBillActionDetails(BillAction billAction, CurrentMembers currentMembers) { - long pricePerMember = billAction.getPrice() / currentMembers.size(); - currentMembers.getMembers().stream() - .map(memberName -> new BillActionDetail(billAction, memberName, pricePerMember, false)) - .forEach(billActionDetailRepository::save); - } - @Transactional public void updateBillAction(String token, Long actionId, BillActionUpdateAppRequest request) { BillAction billAction = billActionRepository.findByAction_Id(actionId) @@ -68,26 +55,9 @@ public void updateBillAction(String token, Long actionId, BillActionUpdateAppReq validateToken(token, billAction); - resetBillActionDetail(billAction, request.price()); - billAction.update(request.title(), request.price()); } - private void resetBillActionDetail(BillAction billAction, Long updatePrice) { - if (!billAction.getPrice().equals(updatePrice)) { - List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(billAction); - int memberCount = billActionDetails.size(); - if (memberCount != 0) { - Long eachPrice = updatePrice / memberCount; - billActionDetails.forEach(billActionDetail -> { - billActionDetail.updatePrice(eachPrice); - billActionDetail.updateIsFixed(false); - } - ); - } - } - } - private void validateToken(String token, BillAction billAction) { Event event = billAction.getEvent(); if (event.isTokenMismatch(token)) { @@ -95,17 +65,16 @@ private void validateToken(String token, BillAction billAction) { } } - private Event getEvent(String eventToken) { - return eventRepository.findByToken(eventToken) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); - } - @Transactional public void deleteBillAction(String token, Long actionId) { Event event = eventRepository.findByToken(token) .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); - billActionDetailRepository.deleteByBillAction_Action_EventAndBillAction_ActionId(event, actionId); billActionRepository.deleteByAction_EventAndActionId(event, actionId); } + + private Event getEvent(String eventToken) { + return eventRepository.findByToken(eventToken) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + } } diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java index b5215688a..245de8cef 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionService.java +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -1,8 +1,6 @@ package server.haengdong.application; import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.IntStream; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -11,8 +9,6 @@ import server.haengdong.domain.action.Action; import server.haengdong.domain.action.ActionRepository; import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.BillActionDetail; -import server.haengdong.domain.action.BillActionDetailRepository; import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.action.CurrentMembers; import server.haengdong.domain.action.MemberAction; @@ -31,7 +27,6 @@ public class MemberActionService { private final MemberActionRepository memberActionRepository; private final EventRepository eventRepository; private final ActionRepository actionRepository; - private final BillActionDetailRepository billActionDetailRepository; private final BillActionRepository billActionRepository; @Transactional @@ -100,37 +95,6 @@ private void resetBillAction(Event event, BillAction billAction) { billAction.getSequence()); CurrentMembers currentMembers = CurrentMembers.of(memberActions); - billActionDetailRepository.deleteAllByBillAction(billAction); - - if (currentMembers.isNotEmpty()) { - Long price = billAction.getPrice(); - int currentMemberCount = currentMembers.size(); - long eachPrice = price / currentMemberCount; - long remainder = price % currentMemberCount; - List<BillActionDetail> billActionDetails = getBillActionDetails( - billAction, - currentMembers, - eachPrice, - remainder - ); - billActionDetailRepository.saveAll(billActionDetails); - } - } - - private List<BillActionDetail> getBillActionDetails( - BillAction billAction, - CurrentMembers currentMembers, - long eachPrice, - long remainder - ) { - List<String> members = currentMembers.getMembers().stream().toList(); - List<BillActionDetail> billActionDetails = IntStream.range(0, members.size() - 1) - .mapToObj(index -> new BillActionDetail(billAction, members.get(index), eachPrice, false)) - .collect(Collectors.toList()); - BillActionDetail lastBillActionDetail = new BillActionDetail(billAction, members.get(members.size() - 1), - eachPrice + remainder, false); - billActionDetails.add(lastBillActionDetail); - - return billActionDetails; + billAction.resetBillActionDetails(currentMembers); } } diff --git a/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java index acd0149f9..21eb17d4a 100644 --- a/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java +++ b/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java @@ -2,13 +2,14 @@ import server.haengdong.domain.action.Action; import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.CurrentMembers; public record BillActionAppRequest( String title, Long price ) { - public BillAction toBillAction(Action action) { - return new BillAction(action, title, price); + public BillAction toBillAction(Action action, CurrentMembers currentMembers) { + return BillAction.create(action, title, price, currentMembers); } } diff --git a/server/src/main/java/server/haengdong/domain/action/BillAction.java b/server/src/main/java/server/haengdong/domain/action/BillAction.java index 0b35040e6..943b40ce5 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillAction.java +++ b/server/src/main/java/server/haengdong/domain/action/BillAction.java @@ -10,7 +10,10 @@ import jakarta.persistence.OneToMany; import jakarta.persistence.OneToOne; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -45,13 +48,8 @@ public class BillAction implements Comparable<BillAction> { private List<BillActionDetail> billActionDetails = new ArrayList<>(); public BillAction(Action action, String title, Long price) { - this(null, action, title, price); - } - - private BillAction(Long id, Action action, String title, Long price) { validateTitle(title); validatePrice(price); - this.id = id; this.action = action; this.title = title.trim(); this.price = price; @@ -70,23 +68,69 @@ private void validatePrice(Long price) { } } + public static BillAction create(Action action, String title, Long price, CurrentMembers currentMembers) { + BillAction billAction = new BillAction(action, title, price); + billAction.resetBillActionDetails(currentMembers); + return billAction; + } + + public void resetBillActionDetails(CurrentMembers currentMembers) { + this.billActionDetails.clear(); + Iterator<Long> priceIterator = distributePrice(currentMembers.size()).iterator(); + + for (String member : currentMembers.getMembers()) { + BillActionDetail billActionDetail = new BillActionDetail(this, member, priceIterator.next(), false); + this.billActionDetails.add(billActionDetail); + } + } + + private void resetBillActionDetails() { + Iterator<Long> priceIterator = distributePrice(billActionDetails.size()).iterator(); + + billActionDetails.forEach(billActionDetail -> { + billActionDetail.updatePrice(priceIterator.next()); + billActionDetail.updateIsFixed(false); + }); + } + + private List<Long> distributePrice(int memberCount) { + if (memberCount == 0) { + return new ArrayList<>(); + } + long eachPrice = price / memberCount; + long remainder = price % memberCount; + + List<Long> results = Stream.generate(() -> eachPrice) + .limit(memberCount - 1) + .collect(Collectors.toList()); + results.add(eachPrice + remainder); + return results; + } + public void update(String title, Long price) { validateTitle(title); validatePrice(price); - this.title = title; + this.title = title.trim(); this.price = price; + resetBillActionDetails(); } - public boolean isSamePrice(Long price) { - return this.price.equals(price); + public void addDetails(List<BillActionDetail> billActionDetails) { + billActionDetails.forEach(this::addDetail); } - public Long getSequence() { - return action.getSequence(); + private void addDetail(BillActionDetail billActionDetail) { + this.billActionDetails.add(billActionDetail); + billActionDetail.setBillAction(this); } - public Event getEvent() { - return action.getEvent(); + public boolean isFixed() { + return billActionDetails.stream() + .anyMatch(BillActionDetail::isFixed); + } + + public boolean isSamePrice(Long price) { + return this.price.equals(price); } public Long findPriceByMemberName(String memberName) { @@ -97,20 +141,12 @@ public Long findPriceByMemberName(String memberName) { .orElse(DEFAULT_PRICE); } - public boolean isFixed() { - return billActionDetails.stream() - .map(BillActionDetail::getPrice) - .distinct() - .count() != 1L; - } - - public void addDetails(List<BillActionDetail> billActionDetails) { - billActionDetails.forEach(this::addDetail); + public Long getSequence() { + return action.getSequence(); } - private void addDetail(BillActionDetail billActionDetail) { - this.billActionDetails.add(billActionDetail); - billActionDetail.setBillAction(this); + public Event getEvent() { + return action.getEvent(); } @Override diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java index 35b331bee..d1d7cfe0f 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java @@ -4,7 +4,6 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; -import server.haengdong.domain.event.Event; @Repository public interface BillActionDetailRepository extends JpaRepository<BillActionDetail, Long> { @@ -15,8 +14,4 @@ public interface BillActionDetailRepository extends JpaRepository<BillActionDeta where bd.billAction = :billAction """) List<BillActionDetail> findAllByBillAction(BillAction billAction); - - void deleteAllByBillAction(BillAction billAction); - - void deleteByBillAction_Action_EventAndBillAction_ActionId(Event event, Long actionId); } From eb919a6f11f75982345639a57058ceb0c3f77c48 Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Thu, 22 Aug 2024 17:19:44 +0900 Subject: [PATCH 162/178] =?UTF-8?q?refactor:=20DB=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=EB=A5=BC=20drop=20=ED=95=A0=20=EC=88=98=20=EC=97=86?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20DB=20user=20=EA=B6=8C=ED=95=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20(#484)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/main/resources/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/resources/config b/server/src/main/resources/config index e3e68ba63..fa4270674 160000 --- a/server/src/main/resources/config +++ b/server/src/main/resources/config @@ -1 +1 @@ -Subproject commit e3e68ba63b49a7f6eaae8ccbd8c8af653ba34f3b +Subproject commit fa42706743e6eb3f4fd8c34618614eff8ae94b3d From 8ef3978f5afe8c749c91abde1078bf9445d6f55e Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Thu, 22 Aug 2024 17:40:21 +0900 Subject: [PATCH 163/178] =?UTF-8?q?refactor:=20DB=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=EB=A5=BC=20drop=20=ED=95=A0=20=EC=88=98=20=EC=97=86?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20DB=20user=20=EA=B6=8C=ED=95=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=ED=95=A9=EB=8B=88=EB=8B=A4.=20(#485)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: webpack, react, typescript 환경 설정 Co-authored-by: pakxe <pigkill40@naver.com>, soi-ha <soy2302ten@gmail.com>, jinhokim98 <rlawlsgh1227@gmail.com> * chore: eslint, prettier 설정 Co-authored-by: JinHo Kim <jinhokim98@users.noreply.github.com> Co-authored-by: Pakxe <pakxe@users.noreply.github.com> * docs: pr 템플릿 및 issue 템플릿 세팅 Co-authored-by: pakxe <pigkill40@naver.com>, soi-ha <soy2302ten@gmail.com>, jinhokim98 <rlawlsgh1227@gmail.com> * docs: issue 템플릿에 타이틀과 관련된 부가 정보 추가 Co-authored-by: pakxe <pigkill40@naver.com>, soi-ha <soy2302ten@gmail.com>, jinhokim98 <rlawlsgh1227@gmail.com> * chore: 모든 install 에 legacy-peer-deps를 사용하도록 설정 Co-authored-by: pakxe <pigkill40@naver.com>, soi-ha <soy2302ten@gmail.com>, jinhokim98 <rlawlsgh1227@gmail.com>, Todari <rhymint@gmail.com> * chore: emotion css props 사용 예제 작성 Co-authored-by: pakxe <pigkill40@naver.com>, soi-ha <soy2302ten@gmail.com>, jinhokim98 <rlawlsgh1227@gmail.com>, Todari <rhymint@gmail.com> * chore: webpack, @emotion/react 라이브러리 설치 Co-authored-by: pakxe <pigkill40@naver.com>, soi-ha <soy2302ten@gmail.com>, jinhokim98 <rlawlsgh1227@gmail.com>, Todari <rhymint@gmail.com> * chore: css props를 사용하기 위해 'jsxImportSource' 옵션 설정 Co-authored-by: pakxe <pigkill40@naver.com>, soi-ha <soy2302ten@gmail.com>, jinhokim98 <rlawlsgh1227@gmail.com>, Todari <rhymint@gmail.com> * chore: css props 사용 위해 모든 파일 최상단에 주석을 자동으로 작성해주도록 플러그인 세팅 Co-authored-by: pakxe <pigkill40@naver.com>, soi-ha <soy2302ten@gmail.com>, jinhokim98 <rlawlsgh1227@gmail.com>, Todari <rhymint@gmail.com> * chore: 개발서버 포트번호 3001 -> 3000 으로 수정 Co-authored-by: pakxe <pigkill40@naver.com>, soi-ha <soy2302ten@gmail.com>, jinhokim98 <rlawlsgh1227@gmail.com>, Todari <rhymint@gmail.com> * chore: prettier에서 useTabs를 사용하지 않도록 제거 Co-authored-by: pakxe <pigkill40@naver.com>, soi-ha <soy2302ten@gmail.com>, jinhokim98 <rlawlsgh1227@gmail.com>, Todari <rhymint@gmail.com> * chore: 여러 명이 co-authored-by로 들어갈 수 있는지 테스트 커밋 Co-authored-by: pakxe <pigkill40@naver.com> Co-authored-by: soi-ha <soy2302ten@gmail.com> Co-authored-by: jinhokim98 <rlawlsgh1227@gmail.com> Co-authored-by: Todari <rhymint@gmail.com> Co-authored-by: pakxe <pigkill40@naver.com> Co-authored-by: soi-ha <soy2302ten@gmail.com> Co-authored-by: jinhokim98 <rlawlsgh1227@gmail.com> Co-authored-by: Todari <rhymint@gmail.com> * chore: 임시로 지웠던 types 옵션을 다시 활성화 Co-authored-by: pakxe <pigkill40@naver.com> Co-authored-by: soi-ha <soy2302ten@gmail.com> Co-authored-by: jinhokim98 <rlawlsgh1227@gmail.com> Co-authored-by: Todari <rhymint@gmail.com> Co-authored-by: pakxe <pigkill40@naver.com> Co-authored-by: soi-ha <soy2302ten@gmail.com> Co-authored-by: jinhokim98 <rlawlsgh1227@gmail.com> Co-authored-by: Todari <rhymint@gmail.com> * chore: 기본 webpack 설정 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * feat: theme, token 구현 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * chore: storybook 설정 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * feat: Button 구현 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * feat: Text 구현 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * fix: webpack 설정 entry 파일 확장자 tsx에서 ts로 변경 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * chore: modify-source-webpack-plugin 의존성 반영되지 않은 것 추가 Co-authored-by: pakxe <pigkill40@naver.com> * chore: css파일을 처리하기 위한 webpack 세팅 Co-authored-by: pakxe <pigkill40@naver.com> * design: 기본 css style 초기화 작업 Co-authored-by: pakxe <pigkill40@naver.com> * feat: 메인 페이지 퍼블리싱 Co-authored-by: pakxe <pigkill40@naver.com> * feat: 이벤트 생성 페이지 퍼블리싱 Co-authored-by: pakxe <pigkill40@naver.com> * feat: 이벤트 생성 완료 페이지 퍼블리싱 Co-authored-by: pakxe <pigkill40@naver.com> * design: 전역 스타일링 설정 Co-authored-by: pakxe <pigkill40@naver.com> * feat: 라우터 셋팅 Co-authored-by: pakxe <pigkill40@naver.com> * feat: 앱의 진입점 설정 Co-authored-by: pakxe <pigkill40@naver.com> * feat: 라우트 경로 설정 Co-authored-by: pakxe <pigkill40@naver.com> * fix: 라우트 이동 시 페이지가 제대로 보이지 않던 문제 해결 Co-authored-by: pakxe <pigkill40@naver.com> * feat: 모달 컴포넌트 생성 Co-authored-by: pakxe <pigkill40@naver.com> * feat: 스위치 컴포넌트 생성 Co-authored-by: pakxe <pigkill40@naver.com> * feat: 초기인원 세팅 기능 퍼블리싱 및 구현 Co-authored-by: pakxe <pigkill40@naver.com> * feat: 행동 추가를 위한 모달 컨텐츠 구현 Co-authored-by: pakxe <pigkill40@naver.com> * feat: 지출 내역 관리 기능구현 Co-authored-by: pakxe <pigkill40@naver.com> * feat: 인원 관리 기능구현 Co-authored-by: pakxe <pigkill40@naver.com> * feat: 행사관리 페이지 퍼블리싱 및 구현 Co-authored-by: pakxe <pigkill40@naver.com> * feat: 해커톤 로그 출력을 위한 임시처리 Co-authored-by: pakxe <pigkill40@naver.com> * feat: 프로젝트 초기 설정 * feat: 엔티티 추가 * refactor: gitignore 수정 * refactor: 엔티티 컬럼명 변경 * chore: path alias 설정 및 lint 마이그레이션 * [FE] 해커톤 범위 디자인시스템 구현 (#36) * feat: FixedButton Component 구현 Co-authored-by: soi-ha <soy2302ten@gmail.com> * feat: Input component 구현 Co-authored-by: soi-ha <soy2302ten@gmail.com> * feat: Title component 구현 Co-authored-by: soi-ha <soy2302ten@gmail.com> * feat: BottomSheet component 구현 Co-authored-by: soi-ha <soy2302ten@gmail.com> * fix: BottomSheet component 빌드 오류 해결 * move: 전체적인 파일 경로 수정정 * move: 전체적인 파일 경로 수정 * fix: npm build를 위한 설정 변경 * feat: IconButton Component 추가 * design: IconButton height가 제대로 적용되지 않는 오류 수정 * feat: npm 배포를 위한 환경설정 및 파일 경로 수정 Co-authored-by: Soyeon Choe <soi-ha@users.noreply.github.com> * style: eslint 적용 * design: globalStyle root BG 변경 * design: globalStyle background 변경 * fix: Title type 변경 * chore: storybook svg 사용을 위한 main.ts 설정 * feat: BillItem component 구현 * feat: InOutItem Component 구현 * feat: StepItemComponent 구현 * chore: storybook preview background color 수정 * chore: tsconfig.json sourcemap 속성 변경 * chore: npm v0.1.0 배포 --------- Co-authored-by: soi-ha <soy2302ten@gmail.com> Co-authored-by: Soyeon Choe <soi-ha@users.noreply.github.com> * feat: CI/CD 파이프라인 구축 (#42) * feat: ci/cd 구축 * fix: ci/cd 디폴트 경로 변경 * fix: ci/cd 디폴트 경로 변경 * fix: ci/cd 디폴트 경로 변경 * fix: ci/cd 디폴트 경로 변경 * fix: ci/cd 디폴트 경로 변경 * fix: ci/cd 디폴트 경로 변경 * feat: cicd 테스트 객체 제거 * feat: cicd 테스트 객체 제거 * feat: 행사 생성 기능 구현 * feat: 지출 내역 추가 기능 구현 * refactor: event의 마지막 action 순서 조회 로직 수정 * refactor: BillAction fetch type 수정 * test: 불필요한 mocking 제거 * refactor: 중요도에 따라 필드 순서 변경 * fix: BillAction 저장 Dto 검증 추가 * [FE] 디자인 시스템 수정 (#46) * chore: storybook 관련 dependency 설치 * fix: Text component 수정 * feat: TextButton Component 구현 * fix: Title Component 수정 * feat: input component background color InputType 추가 및 입력제거 아이콘 변경 * feat: Switch component 구현 * feat: TopNav component 구현 * feat: Tab 컴포넌트 구현 * refactor: Tab type type.ts로 분리 * feature: ExpenseList component 구현 * design: 폰트 size, weight, color 수정 * feat: BillItem에 드래그핸들러 포함 여부를 props로 받을 수 있도록 구현 * design: 드래그핸들러 여부에 따라 패딩을 다르게 하도록 수정 * feat: Flex 컴포넌트 구현 * feat: 잡고 이동할 수 있는 DragHandleItem 컴포넌트 모습 구현 아직 잡고 이동하는 기능은 없습니다. * chore: DragHandleItem 컴포넌트의 스토리북 작성 * feat: BillItem 컴포넌트가 DragHandleItem, Flex 컴포넌트를 사용하도록 수정 * feat: InOutItem 컴포넌트가 DragHandleItem, Flex 컴포넌트를 사용하도록 수정 * fix: 스토리북에서 배열 형태로 모습 테스트를 할 수 있도록 type 수정 * feat: InOutItem에서 드래그 여부를 할 수 있도록 type 추가 * feat: StepItem 컴포넌트가 Flex 컴포넌트를 사용하도록 대체 * feat: children을 포함하는 타입을 빠르게 선언하기 위한 타입 구현 * feat: 카멜 케이스를 케밥 케이스의 문자열로 반환하는 함수 구현 * design: 사용하지 않게된 css 객체 제거 * feat: COLORS 자동완성을 위한 타입 추가 --------- Co-authored-by: 김진호 <rlawlsgh1227@gmail.com> Co-authored-by: Soyeon Choe <soy2302ten@gmail.com> Co-authored-by: pakxe <pigkill40@naver.com> * refactor: BillAction 검증 로직 수정 * refactor: 지출 내역 추가 로직 수정 * feat: BillAction과 Action cascade 옵션과 orphanRemoval 옵션 변경 * test: event save 로직 분리 * test: DisplayName 변경 Co-authored-by: Juhwan Kim <13selfesteem91@naver.com> * test: 경계값 테스트로 변경 Co-authored-by: Juhwan Kim <13selfesteem91@naver.com> * test: 지출 내역 생성 테스트 수정 * feat: PR 후 테스트 리포트 발행 기능 추가 (#56) * test: 미사용 test class 제거 * [BE] 인원 변동 기능 구현 (#47) * feat: 인원 변동 기능 구현 Co-authored-by: kunsanglee <gosmdochee2@gmail.com> * refactor: 메서드 분리 Co-authored-by: kunsanglee <gosmdochee2@gmail.com> * refactor: 코드 컨벤션 Co-authored-by: kunsanglee <gosmdochee2@gmail.com> * refactor: 멤버 액션 생성 클래스 분리 Co-authored-by: kunsanglee <gosmdochee2@gmail.com> * refactor: MemberActionFactory 코드 리팩터링 * refactor: DTO 클래스명 리팩터링 * refactor: MemberActionRepository Lazy Loading 적용 * test: MemberActionFactory createMemberActions 결과 검증 테스트 추가 * refactor: 컨벤션에 맞게 수정 Co-authored-by: kunsanglee <gosmdochee2@gmail.com> * refactor: memberActions를 복사해서 내림차순 정렬하도록 수정, 검증 로직 내부로 이동 Co-authored-by: kunsanglee <gosmdochee2@gmail.com> Co-authored-by: Arachne <jhg2819@naver.com> * refactor: memberActions를 복사해서 내림차순 정렬하도록 수정, 검증 로직 내부로 이동 * refactor: 컨벤션에 맞게 수정 * feat: 사용자 이름이 중복 입력되는 예외 상황 검증 Co-authored-by: kunsanglee <gosmdochee2@gmail.com> Co-authored-by: Arachne <jhg2819@naver.com> * refactor: 메서드 순서 변경 Co-authored-by: Arachne <jhg2819@naver.com> --------- Co-authored-by: kunsanglee <gosmdochee2@gmail.com> Co-authored-by: Arachne <jhg2819@naver.com> authored-by: khabh <khabh@naver.com> * [BE] 패키지 구조 변경 (#62) * chore: 패키지 구조 변경 * test: 패키지 구조 변경 --------- Co-authored-by: Arachneee <jhg2819@naver.com> * feat: api wrapping 객체 생성 (#68) Co-authored-by: JinHo Kim <jinhokim98@users.noreply.github.com> Co-authored-by: Pakxe <pakxe@users.noreply.github.com> Co-authored-by: Soyeon Choe <soi-ha@users.noreply.github.com> * [FE] @svgr/webpack 플러그인 설치 * feat: 행사 정보 조회 기능 구현 (#75) Co-authored-by: kunsanglee <gosmdochee2@gmail.com> * [BE] 설정 파일 서브 모듈 생성 (#82) * feat: 설정 파일을 서브모듈로 관리 Co-authored-by: kunsanglee <gosmdochee2@gmail.com> Co-authored-by: Arachne <jhg2819@naver.com> Co-authored-by: khabh <khabh@naver.com> * feat: 테스트 설정 파일 추가 Co-authored-by: kunsanglee <gosmdochee2@gmail.com> Co-authored-by: Arachne <jhg2819@naver.com> Co-authored-by: khabh <khabh@naver.com> * feat: 도커 파일 내 profile 설정 Co-authored-by: kunsanglee <gosmdochee2@gmail.com> Co-authored-by: Arachne <jhg2819@naver.com> Co-authored-by: khabh <khabh@naver.com> * feat: gitflow에 서브 모듈 설정 Co-authored-by: kunsanglee <gosmdochee2@gmail.com> Co-authored-by: Arachne <jhg2819@naver.com> Co-authored-by: khabh <khabh@naver.com> --------- Co-authored-by: kunsanglee <gosmdochee2@gmail.com> Co-authored-by: Arachne <jhg2819@naver.com> Co-authored-by: khabh <khabh@naver.com> * [BE] 요청 데이터가 맵핑되지 않는 문제 해결 (#86) Co-authored-by: kunsanglee <gosmdochee2@gmail.com> Co-authored-by: Arachneee <jhg2819@naver.com> Co-authored-by: khabh <khabh@naver.com> * feat: 현재 참여 인원 조회 기능 구현 (#70) * design: 탭 컴포넌트 height 소수점 문제 (#51) * design: tab height 소수점 문제 해결 * fix: tab component after 가상태그를 활용해서 div 태그 제거 * chore: 배포, CI 및 테스트 전략 수립 #32 * chore: frontend-push yaml 파일 추가 * chore: eslint-import-resolver-typescript 추가 * chore: eslint explicit-module-boundary-types 옵션 해제 * chore: noUnused tsconfig.json 설정 제거 * chore: eslint no-use-before-define 옵션 제거 * style: eslint 적용 * fix: workflow yml 파일 수정 * feat: 행사 생성 페이지 구현 (#87) * feat: 행사 생성 페이지 디자인시스템 적용 * design : index.css 수정 * feat: 행사 생성 api 연결 * style: lint 적용 * feat: 행사 홈 페이지 구현 (#88) * chore: env와 디자인 시스템 라이브러리 설치 * chore: 현재 불필요한 옵션 비활성화 * chore: env를 사용하기 위한 환경 세팅 * feat: 디자인 시스템 provider 사용 * design: index.css 정한대로 수정 * feat: apiBaseUrl 선언 * feat: router에 Home 페이지 연결 * feat: api호출 시 매번 들어가는 prefix 상수화 * feat: eventId를 타입에 포함시키기 위한 WithEventId 타입 선언 * feat: 지출 내역 추가 api 구현 * feat: 행사 생성 api 구현 * feat: 참여자 목록 갱신 api 구현 * feat: 정산 현황 요청 api 구현 * feat: 행사 이력 조회 api 구현 * feat: 참여자 별 정산 목록 컴포넌트 구현 * feat: 전체 지출 내역 컴포넌트 구현 * feat: router url 논의된 대로 선언 * feat: 정산 현황 검색을 위한 훅 구현 * feat: 스텝 목록을 관리하기 위한 훅 구현 * chore: 정산 현황 목 데이터 작성 * chore: 전체 지출 내역 목 데이터 작성 * feat: 홈 페이지 레이아웃 구현 * feat: 홈 페이지 안에 들어갈 컨텐츠 구현 * feat: Home -> HomePage로 import 할 수 있도록 export 작성 * feat: 스텝 목록에 필요한 타입 선언 * chore: url 경로 포멧 변경에 따른 수정 * chore: package-lock 업로드 * chore: import 개행 추가 * chore: 디자인 시스템 업데이트 * fix: inOutType 대문자로 넘기도록 수정 * feat: TopNav 추가 * chore: 사용하지 않는 util라이브러리 삭제 * chore: dotenv 세팅 수정 * feat: 현재 참여자 검색 component 생성 (#78) * design: Title Component width 100%로 수정 * design: TopNav width 100%로 수정 * fix: index.tsx export 수정 * chore: v0.1.2 배포 * design: input 좌우 1rem 추가 * feat: MainLayout 추가 * chore: v0.1.3 배포 * feat: search 컴포넌트 구현 * design: input 컴포넌트 마진 추가로 searchTerms 마진 추가 * refactor: 사용하지 않는 onChange 제거 * refactor: setKeyword -> setState로 setter라는 의미 명시 * style: early return 뒤 개행 추가 --------- Co-authored-by: 이태훈 <rhymint@gmail.com> * feat: CORS 설정 (#90) * feat: CORS 설정 * refactor: CORS 설정 분리 * test: yml에 CORS 설정 추가 * feat: Origin 추가 * feat: Cors 설정에 HTTP OPTIONS 메서드 추가 --------- Co-authored-by: juha <khabh@naver.com> * feat: 행사 커스텀 예외 처리 (#92) * feat: 행사 커스텀 예외 처리 * feat: 커스텀 예외 적용 * feat: 참여자별 정산 현황 조회 기능 구현 (#77) * feat: api 명세에서 행사 url을 표현하는 용어와 전달 방식 수정 (#98) * feat: 행사 url 명세를 token에서 eventId로 변경 * feat: 행사 url을 헤더가 아닌 바디로 전달 * test: 행사 생성 컨트롤러 테스트 수정 * feat: 행사 생성 응답 dto에 필드명 수정 * feat: 기본 프로파일에서 DB를 MySQL을 H2로 변경 (#102) * feat: 기본 프로파일에서 DB를 MySQL을 H2로 변경 * feat: jpa dll-auto none에서 create로 변경 * refactor: 지출 내역 생성 및 현재 참여 인원 조회 예외 메시지 변경 (#100) * refactor: 지출 내역 생성 예외 메시지 변경 * refactor: 현재 인원 조회 예외 메시지 변경 * refactor: 예외 메시지 전달 방법 수정 * refactor: 참여자별 정산 현황 조회 예외 메시지 변경 (#106) * refactor: 행사 생성 API 예외 메세지 및 DTO 검증 애너테이션 추가 (#103) * refactor: 행사 생성 API 예외 메세지 추가 및 DTO 검증 애너테이션 추가 * refactor: 행사 생성 API EventSaveRequest name을 eventName으로 변경 * refactor: 행사 생성 요청 객체 검증 애너테이션 @Size 제거 * refactor: 연속된 공백 검증 및 예외 메세지 상수 사용하도록 리팩터링 * feat: 행사 관리 페이지 구현 (#107) * style: eslint 적용 * chore: typescript with invalid interface loaded as resolver 해결을 위한 eslint-import-resolver-typescript 설치 * chore: SetInitialParticipatns & SetActionModalContent를 Modal의 index.ts에서 export 추가 * design: HDesignProvider 적용 * design: 행사 관리 페이지 퍼블리싱 * design: 초기 인원 설정 Modal 퍼블리싱 * design: 지출내역 생성 Modal 내부 퍼블리싱 * design: 인원 변동 내역 Modal 내부 퍼블리싱 * feat: TopNav 추가 및 props 추가 * design: BottomSheet 내부 퍼블리싱 (Input overflow시 scroll) * design: 행사 지출/인원 변동 내역 생성 퍼블리싱 * design: switch와 container의 gap 추가 * design: scroll시 모든 자식 요소가 안 보이는 에러 해결 * design: MainLayout 적용 및 root 태그에 height 적용 * design: 지출 내역 생성 Modal 내부 퍼블리싱 * design: 인원 변동 내역 생성 Modal 내부 퍼블리싱 * chore: develop 브랜치 merge로 인한 수정 * chore: 불필요한 import 삭제 * chore: haengdong-design 버전 업데이트 설치 * remove: 사용하지 않는 파일 제거 * chore: TopNav 수정된 디자인 시스템 설치 및 StepList 수정 주석 추가 * style: lint 적용 * feat: Input 값 입력시 다음 Input이 생성되는 hook 기능 구현 * feat: useDynamicInput에 auto focus 및 scrollIntoView 기능 추가 * feat: 초기 인원 설정 및 인원 변동 내역 Modal에 useDynamicInput 적용 * feat: 지출 내역에 대한 기능 구현 (useDynamicInputPairs 훅 생성) * chore: 불필요한 props 제거 및 backlog 주석 추가 * fix: BottomSheet의 onClick을 통해 submit되는 오류 수정 * fix: setParticipants를 분리하여 참여 인원 관리 * fix: setOrder를 분리하여 지출 내역 차수 관리 * chore: 사용하지 않는 상태 제거 * chore: haengdong-design 버전 업데이트 반영 * fix: 작성된 값을 수정할 수 없는 에러 해결 * chore: 에러 발생 수정에 대한 주석 추가 * chore: 디자인시스템 버전 업데이트 반영 * fix: 예외에서 정의한 메세지를 꺼내지 못하는 오류 해결 (#111) * feat: 퍼블리싱된 페이지 매끄럽게 연결 (#114) * chore: 디자인시스템 업데이트 반영 * feat: fixed button 클릭시 router 반영 * feat: 총 지출 금액 추가 및 StepList 연결 * refactor: 인원 변동 요청 형태 변경 (#117) * feat: 액션 이력 조회 기능 구현 (#76) * feat: 액션 이력 조회 기능 구현 Co-authored-by: 3juhwan <13selfesteem91@naver.com> * feat: 액션 이력 조회 반환 형식 변경 * test: 액션 이력 조회 테스트 삭제 --------- Co-authored-by: 3juhwan <13selfesteem91@naver.com> * chore: frontend yml lint 과정 수정 (#120) * fix: 액션 이력이 없는 경우 빈 리스트 반환 (#122) * fix: 액션 이력 조회 오류 수정 (#124) * fix: HaengdongException 적용 안된 부분 적용 * fix: Transactional 추가 및 StepResponse 로직 수정 * fix: StepResponse 로직 수정 (#126) * test: Gradle, Docker 캐싱을 위한 Feature/#121 test (#128) * refactor: Github Actions Gradle, Docker Build 캐싱 * refactor: Docker 사용하는 포트 번호 수정 * refactor: Docker 사용하는 포트 번호 수정 * test * after cache * after cache2 * test: Gardle, Docker 캐싱을 위한 Feature/#121 test2 (#130) * refactor: Github Actions Gradle, Docker Build 캐싱 * refactor: Docker 사용하는 포트 번호 수정 * refactor: Docker 사용하는 포트 번호 수정 * after cache * revert: gradle cache, docker cache (#133) * refactor: 애플리케이션 도커 포트 번호 수정 (#134) * refactor: Docker 빌드 성능 개선 (#138) * refactor: 참여자 정산 현황 로직 리펙토링 (#110) * refactor: 참여자 정산 현황 로직 수정 * refactor: forEach -> stream 변경 * chore: storybook chromatic 배포 (#81) * chore: storybook chromatic workfloe * style: EOL 제거 * chore: storybook 배포를 위한 workflow 설정 * chore: storybook 배포를 위한 workflow 설정 * chore: workflow node 설정 추가 * chore: lint flow path 변경 * chore: run lint 수정 * chore: eslint-config-prettier 추가 * chore: lint 적용 * chore: airbnb 제거 * chore: eslint 설정 수정 * chore: chromatic working directory 변경 * feat: 2차 스프린트 API 연결 (#137) * chore: storybook 관련 dependency 설치 * feat: post api에도 response를 받을 수 있도록 수정 * refactor: parameter가 파스칼케이스인 부분을 카멜 케이스로 수정 * feat: 행사명을 가져오는 api 함수 구현 * feat: interface 수정에 따라 body 변경 * feat: 지출 내역을 추가하는 api 연결 * feat: 최초 참여자를 추가하는 api 연결 * feat: 참여자 수를 조정하는 api 연결 * refactor: name -> title로 파라미터명 수정 * feat: 이벤트아이디를 url에서 불러오는 훅 구현 * feat: 지출 내역, 인원 조정 api연결 후 provider로 전파 * feat: url에서 eventId를 받아오도록 추가 * feat: submit이벤트를 form 엘리먼트에 연결 * remove: 사용하지 않는 파일 제거 * feat: useContext를 사용해 총 가격을 불러오도록 연결 * feat: provider를 사용하기 위한 Layout 컴포넌트 추가 * feat: 디자인시스템 수정에 다른 컴포넌트 호출 형태 변경 * chore: 주석 추가 * remove: 사용하지 않는 파일 제거 * feat: router 에 home, admin 경로에서 띄울 컴포넌트 연결 * fix: 변경된 interface에 맞게 body 수정 * feat: 참여자 목록을 넘겨주지 않고, 참여자 타입 전달 * chore: 불필요한 props 삭제 * feat: 공백된 값 제거 * feat: 네비게이션을 위한 구현 * fix: useStepList훅이 context를 반환하도록 수정 * feat: TopNav 추가 * feat: Admin 페이지 구현 * feat: Home 페이지 구현 * chore: 디자인시스템 라이브러리 업데이트 * chore: await 추가 * feat: stepList를 호출하도록 api 연결 * chore: 사용하지 않는 변수 제거 * chore: lint 적용 * feat: steps를 꺼내서 return하도록 수정 * feat: 인원이 있어야 memberNameList를 갱신하도록 로직 작성 * feat: StepList 의 타입 작성 * design: 불필요한 padding 제거 * chore: 관리 탭에서 StepList를 보여주기 위해 임시로 조건문 제거 * feat: 홈 페이지에서 총 지출 금액 표시 * chore: 디자인 시스템 업데이트 * fix: meta tag 설정 - mixed content, scalable 등 * design: 메인 페이지 및 행사 생성 페이지 디자인 수정 * fix: 새로 고침하면 내역이 출력되지 않는 오류 수정 eventId의 변화에 따라 지출 내역을 다시 호출하도록 종속성을 연결하지 않아서 발생한 문제입니다. * chore: Content-Security-Policy 삭제 * fix: FixedButton disabled 속성 추가 * fix: 행사 이름 입력 페이지 FixedButton disalbed 추가 및 공백 제거 * style: lint 적용 * fix: 불필요한 인자를 넘겨주는 것 제거 * chore: 사용되지 않는 import 제거 * fix: 참여자별 지출 내역을 받아오는 api의 엔드포인트 올바르게 수정 * fix: eventId, 전체 검색 결과에 따라 검색 결과가 보여지도록 수정 * design: 이벤트 홈 타이틀과 탭 사이 공백 제거 * feat: 임시로 행사 이름을 표시하도록 수정 * style: 사용하지 않는 변수 및 import 제거 * design: 전역 스크롤바 숨김 처리 * design: 바텀 버튼만큼 contents 위로 올라오도록 변경 * rename: steList 타입 파일 useStepList 폴더로 이동 후 type.ts로 이름 변경 * chore: 디자인시스템 버전 업데이트 * feat: 검색창 placeholder 참여자 이름 추가 --------- Co-authored-by: 이태훈 <rhymint@gmail.com> Co-authored-by: 김진호 <rlawlsgh1227@gmail.com> Co-authored-by: pakxe <pigkill40@naver.com> * refactor: 도커 계정 관련 정보 secrets으로 수정 (#139) * feat: 2차 스프린트 디자인 시스템 수정 (#83) * design: Title Component width 100%로 수정 * design: TopNav width 100%로 수정 * fix: index.tsx export 수정 * chore: v0.1.2 배포 * design: input 좌우 1rem 추가 * feat: MainLayout 추가 * chore: v0.1.3 배포 * feat: TopNav none 타입 추가 * chore: storybook-addon-react-router-v6 dev dependency 추가 * fix: ExpenseItem button props 넣을 수 있도록 수정 * design: button cursor pointer 전역설정 * refactor: BottomSheet component 구조 수정 * chore: v0.1.4 배포 * refactor: tab components 합성방식으로 변경 * feat: Flex component backgroundColor 받을 수 있도록 변경 * fix: 주석이 xml 내부에서 적용안되던 오류 해결 * chore: v0.1.5 배포 * refactor: flex background prop 로직 처리 방법 변경 * feat: MainLayout backgroundColor prop 추가 * fix: flex backgroundColor defaultValue 제거 * chore: v0.1.6 배포 * fix: MainLayout margin padding으로 변경 * fix: Switch 및 TopNav 내부 로직 변경 * test: Switch storybook 수정 * fix: TopNav navigate currentPath를 이용하도록 수정 * feat: v0.1.18 배포 * fix: TopNav navigate 변경 * design: tab item과 panel 사이에 gap 넣을 수 있도록 설정 및 flex container 사용 * refactor: in out type uppercase로 수정 * design: in out item font size 변경 및 텍스트 바꿔서 작성한 내용 수정 * test: InOutItem storybook 수정 * chore: v0.1.20 배포 * design: hasDragableItem 비활성화 시 마진 수정 * fix: props 네이밍 스토리북에 반영 * fix: navigate 뒤로가기 3번 발생하는 이슈 해결 * chore: v0.1.22 배포 * fix: Switch 내부의 불필요한 로직 제거 * chore: v0.1.23 배포 * fix: navigate path 로직 변경 * fix: 새로고침 됐을 때 해당 location 페이지를 유지하도록 수정 * style: children이 없는 태그 스스로 닫도록 수정 * style: todo 주석 제거 * chore: v0.1.25 배포 * design: fixedButton position 변경 * chore: v0.1.26 배포 * fix: 라우팅 변경 이동 오류 해결 * chore: v0.1.27 배포 * chore: v0.1.28 배포 * fix: location set 로직을 home 모드에서만 작동하도록 변경 * chore: v0.1.29 배포 * fix: TopNav navigation 로직 외부에서 넣도록 변경 * chore: v0.1.30 배포 * fix: index.ts 경로 문제로 제거 * chore: v0.1.13 배포 * chore: v0.1.32 배포 * fix: Fixed Button 하단 고정되도록 변경 * chore: v0.1.33 배포 * v0.1.35 배포 * fix: 가격과 원을 붙여서 표기 * fix: TopNav가 children이 없어도 작동하도록 변경 * fix: children이 필수가 아니도록 변경 * remove: 사용하지 않는 NavSwitch 제거 * chore: 파이프라인 테스트를 위한 push * chore: 파이프라인 테스트를 위한 push * remove: merge를 위한 /sever dir 삭제 * style: lint 적용 --------- Co-authored-by: 이태훈 <rhymint@gmail.com> Co-authored-by: pakxe <pigkill40@naver.com> * chore: server directory 복구 (#150) * fix: gradlew 권한 버그 수정 (#152) * remove: 클라이언트 코드 삭제 * refactor: CD workflow main, develop 분리 (#163) * refactor: CD workflow main, develop 분리 및 dockerfile 수정 * refactor: trigger test 브랜치 추가 * refactor: feature/#147 에 push test * refactor: github actions self-hosted runner tag 추가 * refactor: feature/#147 runner 구분 테스트 * refactor: feature/#147 prod runner 구분 테스트 * refactor: feature/#147 prod runner 구분 테스트2 * refactor: feature/#147 prod runner 구분 테스트3 * refactor: feature/#147 prod runner 구분 테스트3 * refactor: prod, dev yml 분리 완료 및 서버 테스트 완료 * feat: 로그 모니터링 환경 구축 (#169) * feat: 예외메시지 구체화 (#161) * feat: 예외 핸들링 추가 * refactor: 예외 메시지 구체화 및 검증 역할 변경 * feat: 에러 코드 추가 * style: 개행 제거 * refactor: 멤버 액션 예외 ErrorCode 분리 * feat: 로깅 추가 * refactor: 액션 이력 조회 리펙토링 (#141) * feat: 멤버 액션 삭제 기능 구현 (#181) * feat: 액션 삭제 기능 구현 중 지출 삭제 가능, 인원 삭제는 아직입니다. * feat: 멤버 액션 삭제 구현 Co-authored-by: pakxe <pigkill40@naver.com> Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <gosmdochee2@gmail.com> * feat: 맴버 액션 삭제 기능 구현 * refactor: api 매개변수에 값 넣도록 수정 * fix: 테스트 코드에 action 올바르게 사용하도록 수정 --------- Co-authored-by: 김진호 <rlawlsgh1227@gmail.com> Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: pakxe <pigkill40@naver.com> * feat: ERD svg 생성하여 스키마 변경에 대한 이력 관리 (#190) * feat: 지출 액션 수정 기능 구현 (#180) * feat: 지출 액션 삭제 기능 구현 (#179) * feat: 행사의 전체 참여자 중 특정 참여자의 멤버 액션을 모두 삭제하는 기능 구현 (#185) * feat: 행사의 전체 참여자 중 특정 참여자의 멤버 액션을 모두 삭제하는 기능 구현 * test: eventId String으로 변경 * fix: 다른 행사에 있는 멤버 액션도 지워지는 버그 수정 * refactor: 전체 참여자 중에서 특정 참여자를 전부 삭제하는 메서드명 변경 * refactor: 전체 참여자 중에서 특정 참여자를 전부 삭제하는 메서드명 변경 * refactor: MemberActionController 메서드 파라미터 컨벤션 반영 * refactor: conflict resolve * refactor: conflict resolve * feat: 행사에 참여한 전체 인원 조회 기능 구현 (#195) * feat: 행사에 참여한 전체 인원 조회 기능 구현 Co-authored-by: 3juhwan <13selfesteem91@naver.com> * refactor: EventServiceTest, MemberActionRepository 코드 리팩터링 * fix: workflows runs-on self-hosted로 변경 Co-authored-by: 3juhwan <13selfesteem91@naver.com> * fix: workflows runs-on self-hosted로 변경 Co-authored-by: 3juhwan <13selfesteem91@naver.com> * fix: workflows runs-on self-hosted로 변경 Co-authored-by: 3juhwan <13selfesteem91@naver.com> --------- Co-authored-by: kunsanglee <gosmdochee2@gmail.com> * feat: 행사 참여 인원 이름 변경 기능 구현 (#197) * feat: 행사 참여 인원 이름 변경 기능 구현 * refactor: 지출 액션 수정 기능 리펙토링 --------- Co-authored-by: Arachneee <jhg2819@naver.com> * refactor: API 엔드포인트 수정 (#200) * refactor: 멤버 액션, 지출 액션 관련 API 엔드포인트 수정 * refactor: 요청 url에 token을 eventId로 수정 --------- Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: Arachne <66822642+Arachneee@users.noreply.github.com> * feat: 테스트 데이터 클리너 구현 (#199) * feat: 테스트 데이터 클리너 구현 * feat: 테스트 클리너 상수, 메서드 분리 * refactor: 데이터베이스 클리너 적용 * feat: 행사 관리자 비밀번호 추가 (#213) * feat: 이벤트 비밀번호 추 * test: 테스트 공통 설정 클래스 분리 * feat: 어드민 인터셉터 추가 및 jwt 설정 추가 * feat: 이벤트 로그인 기능 구현 Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Co-authored-by: khabh <khabh@naver.com> * feat: 쿠키 설정 분리 Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Co-authored-by: khabh <khabh@naver.com> * submodule 업데이트 * style: 주석 제거 Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Co-authored-by: khabh <khabh@naver.com> * refactor: 로컬 환경 쿠키 secure 옵션 제거 Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Co-authored-by: khabh <khabh@naver.com> * test: 접근제어자 수정 Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Co-authored-by: khabh <khabh@naver.com> * test: 개행 추가 Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Co-authored-by: khabh <khabh@naver.com> --------- Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Co-authored-by: khabh <khabh@naver.com> * fix: 쿠키 인증 버그 수정 (#222) Co-authored-by: khabh <khabh@naver.com> * fix: 쿠키 인증 버그 수정 (#235) * refactor: 에러 코드 재정의 (#227) * refactor: 에러 코드 재정의 Co-authored-by: 3juhwan <13selfesteem91@naver.com> * fix: 변수를 받는 예외 메세지 수정 Co-authored-by: 3juhwan <13selfesteem91@naver.com> --------- Co-authored-by: kunsanglee <gosmdochee2@gmail.com> Co-authored-by: Arachne <66822642+Arachneee@users.noreply.github.com> * fix: 쿠키 저장 오류 2차 수정 (#237) * fix: 쿠키 인증 버그 수정 Co-authored-by: khabh <khabh@naver.com> * fix: 쿠키 인증 버그 수정 --------- Co-authored-by: khabh <khabh@naver.com> * feat: REST docs를 통한 문서화 (#238) * feat: REST Docs 적용 * feat: REST Docs prettyPrint 및 snippets 적용 * feat: REST Docs에 예외 항목 추가 * test: 행사 액션 이력 조회 테스트 추가 * refactor: 중복된 http-request snippet 제거 * refactor: 사용되지 않는 snippet 제거 * refactor: 빌드 시 자동으로 문서 최신화하도록 gradle 설정 추가 * fix: CookieProperties에 sameSite 옵션 추가 --------- Co-authored-by: Arachne <66822642+Arachneee@users.noreply.github.com> * fix: JWT 유효기간 만료 버그 수정 (#248) * fix: JWT 기간 오류 수정 * fix: JWT 기간 오류 수정 * feat: 관리자 권한 확인 API 구현 (#259) * feat: 관리자 권한 확인 API 구현 * backend-pull-request workflow 파일 수정 * feat: HTTP Method를 POST에서 GET으로 변경 * fix: 참여자 삭제 서비스 메서드에 Transactional 추가 (#265) Co-authored-by: 3juhwan <13selfesteem91@naver.com> * refactor: application.yml metrics 추가 (#269) * feat: CI/CD 숙제 (#290) * feat: CI/CD 숙제 (#291) * refactor: 행사 참여 인원 이름 변경 api 수정 (#268) * refactor: 회원 이름 변경 api 여러명으로 추가 * style: 메소드 순서 변경 * fix: rest docs 저장 파일 위치 변경 (#273) * fix: 어드민 권한 확인 불가 버그 수정 (#275) * fix: 행사 로그인 불가 버그 수정 (#283) * fix: CI/CD 트리거 조건에서 server 폴더 조건 제거 (#308) * fix: CI 트리거 조건을 수정 * feat: be-dev CD 트리거 조건에서 server 폴더 제거 * feat: pr 머지시 issue close 기능 추가 (#309) * refactor: yml, Dockerfile TZ Asia/Seoul 적용 (#305) Co-authored-by: Arachne <66822642+Arachneee@users.noreply.github.com> * refactor: actuator health 엔드포인트 설정 변경 (#303) * feat: actuator health 엔드포인트 설정 변경 * refactor: AdminInterceptor log level 변경 --------- Co-authored-by: Juhwan Kim <13selfesteem91@naver.com> * feat: 서버 로그 볼륨 마운트 설정 (#300) * feat: 로그 파일 볼륨 설정 * feat: 볼륨 이름 지정 * feat: LogBack 롤링 정책 수정, 로그 레벨에 따른 분리 (#332) * feat: Logback 로그 레벨 분리 * feat: Lockback 로그 레벨 분리 --------- Co-authored-by: Arachneee <jhg2819@naver.com> * fix: 서브 모듈 프로파일 오타 수정 (#334) * refactor: 현재 참여 인원 목록 조회 API 반환 형식 수정 (#361) * feat: BillActionDetail 베이스 코드 생성 (#363) * feat: 액션 이력 조회 v2 기능 구현 (#375) * [BE] 행사 참여 인원 또는 지출 총액 변동시 차등 정산 초기화 기능 구현 (#370) * feat: 지출 액션 수정시 지출 디테일 초기화 기능 구현 * feat: 맴버 액션 삭제시 지출 디테일 초기화 기능 구현 * feat: 맴버 삭제시 지출 디테일 초기화 기능 구현 * fix: 버그 수정 * fix: 버그 수정 * feat: 요구사항 변경에 따른 지출 내역 추가, 지출 액션 삭제 API 수정 (#373) * feat: 지출 내역 추가 시, 상세 내역 생성 로직 추가 * feat: 지출 내역 삭제 시, 상세 내역 삭제 로직 추가 * fix: 멤버가 없는 상황에 대해 0으로 나누는 상황 방지 * refactor: 참여자별 정산 현황 조회 및 액션 이력 조회 수정 (#377) * refactor: BillActionDetail 변경 사항을 반영하여 참여자별 정산 현황 조회하도록 수정 * refactor: 액션 이력 조회 시 지출 액션 고정 금액 설정 여부 필드 추가 * refactor: isFixed 필드 삭제 * refactor: 메서드 이름 변경 * fix: BillAction 변경 로직 수정 * feat: 참여자 개별 지출 금액 수정 및 조회 기능 구현 (#378) * feat: 참여자 개별 지출 금액 수정 기능 구현 * refactor: BillActionDetailService 코드 리팩터링 * docs: restdocs 작성 * feat: 참여자별 지출 금액 조회 기능 구현 * docs: index.adoc에 billActionDetail.adoc 추가 * refactor: 충돌 해결 * feat: 에러를 재현할 수 있는 로그로 수정 (#392) * feat: 로깅에 요청 정보 포함 * feat: 개발 환경 ddl update로 변경 * feat: 예외 처리 및 로깅 형식 수정 (#394) * fix: 리스트 형태의 요청 바디에 null을 넣으면 500이 뜨는 에러 수정 * feat: 로그를 json 형태로 수정 * feat: 예외 처리 및 로깅 형식 수정 (#395) * fix: 리스트 형태의 요청 바디에 null을 넣으면 500이 뜨는 에러 수정 * feat: 로그를 json 형태로 수정 * feat: 로그를 json 인덴트 추가 * refactor: BillActionDetail isFixed 추가 (#405) * fix: 로깅 적용 후 예외 응답 불가 버그 수정 (#413) * feat: 액션 이력 조회 stepName 추가 (#420) * feat: 이슈, PR 템플릿 추가 (#160) (#426) * fix: BillAction 수정시 BillDetail 초기화 안되는 버그 수정 * fix: BillAction 수정시 BillDetail 초기화 안되는 버그 수정 * fix: BillAction 수정시 BillDetail 초기화 안되는 버그 수정 * docs: pr issue close 삭제 * feat: 행사 비밀번호 암호화 추가 (#429) * feat: 행사 비밀번호 암호화 추가 * refactor: 비밀번호 암호화 로직 수정 * fix: MessageDigest를 싱글톤으로 관리하지 않도록 수정 --------- Co-authored-by: 3juhwan <13selfesteem91@naver.com> * fix: BillActionDetail 초기화시 totalPrice와 정합성 안맞는 버그 수정 (#460) * fix: BillActionDetail 초기화시 totalPrice와 정합성 안맞는 버그 수정 * refactor: BillActionDetail 초기화 로직 BillAction으로 위임 * style: 메소드 이름 수정 * refactor: BillActionDetail 계산 공통 로직 메소드 분리 * fix: price 분배 로직 버그 수정 * style: 미사용 필드 제거 --------- Co-authored-by: Arachneee <jhg2819@naver.com> * refactor: DB 데이터를 drop 할 수 없도록 DB user 권한 수정 (#484) --------- Co-authored-by: 이태훈 <rhymint@gmail.com> Co-authored-by: pakxe <pigkill40@naver.com>, soi-ha <soy2302ten@gmail.com>, jinhokim98 <rlawlsgh1227@gmail.com> Co-authored-by: JinHo Kim <jinhokim98@users.noreply.github.com> Co-authored-by: Pakxe <pakxe@users.noreply.github.com> Co-authored-by: pakxe <pigkill40@naver.com> Co-authored-by: soi-ha <soy2302ten@gmail.com> Co-authored-by: TaehunLee <85233397+Todari@users.noreply.github.com> Co-authored-by: Soyeon Choe <soi-ha@users.noreply.github.com> Co-authored-by: Arachne <66822642+Arachneee@users.noreply.github.com> Co-authored-by: Arachneee <jhg2819@naver.com> Co-authored-by: juha <khabh@naver.com> Co-authored-by: Juhwan Kim <13selfesteem91@naver.com> Co-authored-by: JUHA <84626225+khabh@users.noreply.github.com> Co-authored-by: Soyeon Choe <77609591+soi-ha@users.noreply.github.com> Co-authored-by: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> Co-authored-by: Pakxe <64801796+pakxe@users.noreply.github.com> --- .github/workflows/backend-dev.yml | 72 ++++ .github/workflows/backend-prod.yml | 74 ++++ .github/workflows/backend-pull-request.yml | 44 ++ .gitmodules | 4 + client/.gitkeep | 0 server/.gitignore | 244 +++++++++++ server/.gitkeep | 0 server/Dockerfile | 9 + server/build.gradle | 86 ++++ server/docs/24-08-04-erd.sql | 65 +++ server/docs/24-08-04-erd.svg | 4 + server/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43453 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + server/gradlew | 249 ++++++++++++ server/gradlew.bat | 92 +++++ server/settings.gradle | 1 + server/src/docs/asciidoc/billAction.adoc | 121 ++++++ .../src/docs/asciidoc/billActionDetail.adoc | 93 +++++ server/src/docs/asciidoc/event.adoc | 205 ++++++++++ server/src/docs/asciidoc/index.adoc | 15 + server/src/docs/asciidoc/memberAction.adoc | 100 +++++ .../src/docs/asciidoc/memberBillReport.adoc | 17 + .../haengdong/HaengdongApplication.java | 15 + .../haengdong/application/ActionService.java | 39 ++ .../haengdong/application/AuthService.java | 41 ++ .../application/BillActionDetailService.java | 76 ++++ .../application/BillActionService.java | 80 ++++ .../haengdong/application/EventService.java | 165 ++++++++ .../application/MemberActionFactory.java | 62 +++ .../application/MemberActionService.java | 100 +++++ .../request/BillActionAppRequest.java | 15 + .../BillActionDetailUpdateAppRequest.java | 8 + .../BillActionDetailsUpdateAppRequest.java | 8 + .../request/BillActionUpdateAppRequest.java | 7 + .../application/request/EventAppRequest.java | 10 + .../request/EventLoginAppRequest.java | 4 + .../request/MemberActionSaveAppRequest.java | 12 + .../request/MemberActionsSaveAppRequest.java | 6 + .../request/MemberNameUpdateAppRequest.java | 7 + .../request/MemberNamesUpdateAppRequest.java | 8 + .../response/ActionAppResponse.java | 61 +++ .../response/BillActionDetailAppResponse.java | 18 + .../BillActionDetailsAppResponse.java | 14 + .../response/CurrentMemberAppResponse.java | 10 + .../response/EventAppResponse.java | 10 + .../response/EventDetailAppResponse.java | 10 + .../response/MemberBillReportAppResponse.java | 4 + .../response/MembersAppResponse.java | 8 + .../haengdong/config/AdminInterceptor.java | 51 +++ .../config/RequestServletFilter.java | 23 ++ .../server/haengdong/config/WebMvcConfig.java | 66 +++ .../haengdong/domain/TokenProvider.java | 12 + .../haengdong/domain/action/Action.java | 42 ++ .../domain/action/ActionRepository.java | 23 ++ .../haengdong/domain/action/BillAction.java | 156 +++++++ .../domain/action/BillActionDetail.java | 57 +++ .../action/BillActionDetailRepository.java | 17 + .../domain/action/BillActionRepository.java | 27 ++ .../domain/action/CurrentMembers.java | 81 ++++ .../haengdong/domain/action/MemberAction.java | 76 ++++ .../domain/action/MemberActionRepository.java | 53 +++ .../domain/action/MemberActionStatus.java | 19 + .../domain/action/MemberBillReport.java | 75 ++++ .../domain/action/MemberGroupIdProvider.java | 11 + .../server/haengdong/domain/event/Event.java | 70 ++++ .../domain/event/EventRepository.java | 11 + .../haengdong/domain/event/EventStep.java | 28 ++ .../domain/event/EventTokenProvider.java | 12 + .../haengdong/domain/event/Password.java | 52 +++ .../exception/AuthenticationException.java | 19 + .../haengdong/exception/ErrorResponse.java | 15 + .../exception/GlobalExceptionHandler.java | 90 +++++ .../exception/HaengdongErrorCode.java | 69 ++++ .../exception/HaengdongException.java | 19 + .../auth/AuthenticationExtractor.java | 23 ++ .../infrastructure/auth/CookieProperties.java | 15 + .../infrastructure/auth/JwtTokenProvider.java | 54 +++ .../infrastructure/auth/TokenProperties.java | 7 + .../presentation/ActionController.java | 26 ++ .../presentation/BillActionController.java | 55 +++ .../BillActionDetailController.java | 42 ++ .../presentation/EventController.java | 120 ++++++ .../presentation/MemberActionController.java | 60 +++ .../BillActionDetailUpdateRequest.java | 21 + .../BillActionDetailsUpdateRequest.java | 16 + .../request/BillActionSaveRequest.java | 19 + .../request/BillActionUpdateRequest.java | 18 + .../request/BillActionsSaveRequest.java | 18 + .../request/EventLoginRequest.java | 14 + .../request/EventSaveRequest.java | 18 + .../request/MemberActionsSaveRequest.java | 25 ++ .../request/MemberNameUpdateRequest.java | 18 + .../request/MemberNamesUpdateRequest.java | 17 + .../presentation/response/ActionResponse.java | 26 ++ .../response/ActionResponse2.java | 22 + .../response/ActionsResponse.java | 14 + .../response/BillActionDetailResponse.java | 18 + .../response/BillActionDetailsResponse.java | 16 + .../response/CurrentMembersResponse.java | 15 + .../response/EventDetailResponse.java | 10 + .../presentation/response/EventResponse.java | 10 + .../response/MemberBillReportResponse.java | 10 + .../response/MemberBillReportsResponse.java | 15 + .../response/MembersResponse.java | 13 + .../presentation/response/StepResponse.java | 27 ++ .../presentation/response/StepsResponse.java | 56 +++ server/src/main/resources/application.yml | 66 +++ server/src/main/resources/config | 1 + server/src/main/resources/logback-spring.xml | 97 +++++ .../application/ActionServiceTest.java | 91 +++++ .../BillActionDetailServiceTest.java | 111 +++++ .../application/BillActionServiceTest.java | 229 +++++++++++ .../application/EventServiceTest.java | 231 +++++++++++ .../application/MemberActionFactoryTest.java | 223 ++++++++++ .../application/MemberActionServiceTest.java | 251 ++++++++++++ .../application/ServiceTestSupport.java | 11 + .../docs/ActionControllerDocsTest.java | 70 ++++ .../docs/BillActionControllerDocsTest.java | 128 ++++++ .../BillActionDetailControllerDocsTest.java | 127 ++++++ .../docs/EventControllerDocsTest.java | 381 ++++++++++++++++++ .../docs/MemberActionControllerDocsTest.java | 157 ++++++++ .../haengdong/docs/RestDocsSupport.java | 28 ++ .../haengdong/domain/action/ActionTest.java | 31 ++ .../domain/action/BillActionTest.java | 89 ++++ .../domain/action/CurrentMembersTest.java | 97 +++++ .../domain/action/MemberBillReportTest.java | 56 +++ .../haengdong/domain/event/EventTest.java | 65 +++ .../haengdong/domain/event/PasswordTest.java | 19 + .../presentation/ActionControllerTest.java | 36 ++ .../BillActionControllerTest.java | 97 +++++ .../BillActionDetailControllerTest.java | 56 +++ .../presentation/ControllerTestSupport.java | 53 +++ .../presentation/EventControllerTest.java | 111 +++++ .../MemberActionControllerTest.java | 74 ++++ .../response/StepsResponseTest.java | 63 +++ .../support/extension/DatabaseCleaner.java | 52 +++ .../extension/DatabaseCleanerExtension.java | 19 + .../haengdong/support/fixture/Fixture.java | 15 + 138 files changed, 7447 insertions(+) create mode 100644 .github/workflows/backend-dev.yml create mode 100644 .github/workflows/backend-prod.yml create mode 100644 .github/workflows/backend-pull-request.yml create mode 100644 .gitmodules delete mode 100644 client/.gitkeep create mode 100644 server/.gitignore delete mode 100644 server/.gitkeep create mode 100644 server/Dockerfile create mode 100644 server/build.gradle create mode 100644 server/docs/24-08-04-erd.sql create mode 100644 server/docs/24-08-04-erd.svg create mode 100644 server/gradle/wrapper/gradle-wrapper.jar create mode 100644 server/gradle/wrapper/gradle-wrapper.properties create mode 100644 server/gradlew create mode 100644 server/gradlew.bat create mode 100644 server/settings.gradle create mode 100644 server/src/docs/asciidoc/billAction.adoc create mode 100644 server/src/docs/asciidoc/billActionDetail.adoc create mode 100644 server/src/docs/asciidoc/event.adoc create mode 100644 server/src/docs/asciidoc/index.adoc create mode 100644 server/src/docs/asciidoc/memberAction.adoc create mode 100644 server/src/docs/asciidoc/memberBillReport.adoc create mode 100644 server/src/main/java/server/haengdong/HaengdongApplication.java create mode 100644 server/src/main/java/server/haengdong/application/ActionService.java create mode 100644 server/src/main/java/server/haengdong/application/AuthService.java create mode 100644 server/src/main/java/server/haengdong/application/BillActionDetailService.java create mode 100644 server/src/main/java/server/haengdong/application/BillActionService.java create mode 100644 server/src/main/java/server/haengdong/application/EventService.java create mode 100644 server/src/main/java/server/haengdong/application/MemberActionFactory.java create mode 100644 server/src/main/java/server/haengdong/application/MemberActionService.java create mode 100644 server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/BillActionDetailsUpdateAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/BillActionUpdateAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/EventAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/EventLoginAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/MemberNamesUpdateAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/response/ActionAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/BillActionDetailsAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/EventAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/MembersAppResponse.java create mode 100644 server/src/main/java/server/haengdong/config/AdminInterceptor.java create mode 100644 server/src/main/java/server/haengdong/config/RequestServletFilter.java create mode 100644 server/src/main/java/server/haengdong/config/WebMvcConfig.java create mode 100644 server/src/main/java/server/haengdong/domain/TokenProvider.java create mode 100644 server/src/main/java/server/haengdong/domain/action/Action.java create mode 100644 server/src/main/java/server/haengdong/domain/action/ActionRepository.java create mode 100644 server/src/main/java/server/haengdong/domain/action/BillAction.java create mode 100644 server/src/main/java/server/haengdong/domain/action/BillActionDetail.java create mode 100644 server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java create mode 100644 server/src/main/java/server/haengdong/domain/action/BillActionRepository.java create mode 100644 server/src/main/java/server/haengdong/domain/action/CurrentMembers.java create mode 100644 server/src/main/java/server/haengdong/domain/action/MemberAction.java create mode 100644 server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java create mode 100644 server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java create mode 100644 server/src/main/java/server/haengdong/domain/action/MemberBillReport.java create mode 100644 server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java create mode 100644 server/src/main/java/server/haengdong/domain/event/Event.java create mode 100644 server/src/main/java/server/haengdong/domain/event/EventRepository.java create mode 100644 server/src/main/java/server/haengdong/domain/event/EventStep.java create mode 100644 server/src/main/java/server/haengdong/domain/event/EventTokenProvider.java create mode 100644 server/src/main/java/server/haengdong/domain/event/Password.java create mode 100644 server/src/main/java/server/haengdong/exception/AuthenticationException.java create mode 100644 server/src/main/java/server/haengdong/exception/ErrorResponse.java create mode 100644 server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java create mode 100644 server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java create mode 100644 server/src/main/java/server/haengdong/exception/HaengdongException.java create mode 100644 server/src/main/java/server/haengdong/infrastructure/auth/AuthenticationExtractor.java create mode 100644 server/src/main/java/server/haengdong/infrastructure/auth/CookieProperties.java create mode 100644 server/src/main/java/server/haengdong/infrastructure/auth/JwtTokenProvider.java create mode 100644 server/src/main/java/server/haengdong/infrastructure/auth/TokenProperties.java create mode 100644 server/src/main/java/server/haengdong/presentation/ActionController.java create mode 100644 server/src/main/java/server/haengdong/presentation/BillActionController.java create mode 100644 server/src/main/java/server/haengdong/presentation/BillActionDetailController.java create mode 100644 server/src/main/java/server/haengdong/presentation/EventController.java create mode 100644 server/src/main/java/server/haengdong/presentation/MemberActionController.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/EventLoginRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/MemberNameUpdateRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/ActionResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/BillActionDetailsResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/EventResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/MembersResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/StepResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/StepsResponse.java create mode 100644 server/src/main/resources/application.yml create mode 160000 server/src/main/resources/config create mode 100644 server/src/main/resources/logback-spring.xml create mode 100644 server/src/test/java/server/haengdong/application/ActionServiceTest.java create mode 100644 server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java create mode 100644 server/src/test/java/server/haengdong/application/BillActionServiceTest.java create mode 100644 server/src/test/java/server/haengdong/application/EventServiceTest.java create mode 100644 server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java create mode 100644 server/src/test/java/server/haengdong/application/MemberActionServiceTest.java create mode 100644 server/src/test/java/server/haengdong/application/ServiceTestSupport.java create mode 100644 server/src/test/java/server/haengdong/docs/ActionControllerDocsTest.java create mode 100644 server/src/test/java/server/haengdong/docs/BillActionControllerDocsTest.java create mode 100644 server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java create mode 100644 server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java create mode 100644 server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java create mode 100644 server/src/test/java/server/haengdong/docs/RestDocsSupport.java create mode 100644 server/src/test/java/server/haengdong/domain/action/ActionTest.java create mode 100644 server/src/test/java/server/haengdong/domain/action/BillActionTest.java create mode 100644 server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java create mode 100644 server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java create mode 100644 server/src/test/java/server/haengdong/domain/event/EventTest.java create mode 100644 server/src/test/java/server/haengdong/domain/event/PasswordTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/ActionControllerTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java create mode 100644 server/src/test/java/server/haengdong/presentation/EventControllerTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java create mode 100644 server/src/test/java/server/haengdong/support/extension/DatabaseCleaner.java create mode 100644 server/src/test/java/server/haengdong/support/extension/DatabaseCleanerExtension.java create mode 100644 server/src/test/java/server/haengdong/support/fixture/Fixture.java diff --git a/.github/workflows/backend-dev.yml b/.github/workflows/backend-dev.yml new file mode 100644 index 000000000..a3257f028 --- /dev/null +++ b/.github/workflows/backend-dev.yml @@ -0,0 +1,72 @@ +name: backend-push + +on: + push: + branches: [ "be-dev" ] + +jobs: + build: + runs-on: [ self-hosted, backend-dev ] + + defaults: + run: + shell: bash + working-directory: ./server + + permissions: + contents: read + + steps: + - name: CheckOut + uses: actions/checkout@v4 + with: + token: ${{secrets.CONFIG_SUBMODULE_TOKEN}} + submodules: true + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Test with Gradle Wrapper + run: ./gradlew clean build + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Set up Docker BuildX + uses: docker/setup-buildx-action@v3 + + - name: Build and push + run: | + docker buildx build --platform linux/arm64 -t \ + ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }} --push . + + deploy: + needs: build + runs-on: [ self-hosted, backend-dev ] + steps: + - name: Docker remove + run: | + CONTAINER_IDS=$(sudo docker ps -qa) + if [ -n "$CONTAINER_IDS" ]; then + sudo docker rm -f $CONTAINER_IDS + else + echo "No running containers found." + fi + + - name: Docker Image pull + run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }} + + - name: Docker run + run: sudo docker run -d -p 8080:8080 -e SPRING_PROFILES_ACTIVE=dev -v log-volume:/app/logs --name haengdong-backend ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }} diff --git a/.github/workflows/backend-prod.yml b/.github/workflows/backend-prod.yml new file mode 100644 index 000000000..f7daacd33 --- /dev/null +++ b/.github/workflows/backend-prod.yml @@ -0,0 +1,74 @@ +name: backend-push + +on: + push: + branches: [ "main" ] + paths: + - 'server/**' + +jobs: + build: + runs-on: ubuntu-latest + + defaults: + run: + shell: bash + working-directory: ./server + + permissions: + contents: read + + steps: + - name: CheckOut + uses: actions/checkout@v4 + with: + token: ${{secrets.CONFIG_SUBMODULE_TOKEN}} + submodules: true + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Test with Gradle Wrapper + run: ./gradlew clean build + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Set up Docker BuildX + uses: docker/setup-buildx-action@v3 + + - name: Build and push + run: | + docker buildx build --platform linux/arm64 -t \ + ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }} --push . + + deploy: + needs: build + runs-on: [ self-hosted, backend-prod ] + steps: + - name: Docker remove + run: | + CONTAINER_IDS=$(sudo docker ps -qa) + if [ -n "$CONTAINER_IDS" ]; then + sudo docker rm -f $CONTAINER_IDS + else + echo "No running containers found." + fi + + - name: Docker Image pull + run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }} + + - name: Docker run + run: sudo docker run -d -p 8080:8080 -e SPRING_PROFILES_ACTIVE=prod -v log-volume:/app/logs --name haengdong-backend ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }} diff --git a/.github/workflows/backend-pull-request.yml b/.github/workflows/backend-pull-request.yml new file mode 100644 index 000000000..df008fd97 --- /dev/null +++ b/.github/workflows/backend-pull-request.yml @@ -0,0 +1,44 @@ +name: backend-pull-request + +on: + pull_request: + branches: [ "main", "be-dev" ] + +jobs: + build: + runs-on: [ ubuntu-latest ] + + defaults: + run: + working-directory: ./server + + steps: + - name: CheckOut + uses: actions/checkout@v4 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Test with Gradle Wrapper + run: ./gradlew clean build + + - name: publish unit test results + uses: EnricoMi/publish-unit-test-result-action@v2 + if: always() + with: + files: server/build/test-results/test/TEST-*.xml + + - name: add comments to a pull request + uses: mikepenz/action-junit-report@v3 + if: always() + with: + report_paths: server/build/test-results/test/TEST-*.xml diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..d013a93bc --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "server/src/main/resources/config"] + branch = main + path = server/src/main/resources/config + url = https://github.com/woowacourse-teams/2024-haeng-dong-config.git diff --git a/client/.gitkeep b/client/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/server/.gitignore b/server/.gitignore new file mode 100644 index 000000000..671ee930b --- /dev/null +++ b/server/.gitignore @@ -0,0 +1,244 @@ +# Created by https://www.toptal.com/developers/gitignore/api/java,intellij,gradle,macos,windows,linux +# Edit at https://www.toptal.com/developers/gitignore?templates=java,intellij,gradle,macos,windows,linux + +### Intellij ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +# Azure Toolkit for IntelliJ plugin +# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij +.idea/**/azureSettings.xml + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### Gradle ### +.gradle +**/build/ +!src/**/build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Avoid ignore Gradle wrappper properties +!gradle-wrapper.properties + +# Cache of project +.gradletasknamecache + +# Eclipse Gradle plugin generated files +# Eclipse Core +.project +# JDT-specific (Eclipse Java Development Tools) +.classpath + +### Gradle Patch ### +# Java heap dump +*.hprof + +# End of https://www.toptal.com/developers/gitignore/api/java,intellij,gradle,macos,windows,linux diff --git a/server/.gitkeep b/server/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/server/Dockerfile b/server/Dockerfile new file mode 100644 index 000000000..df2cf44e0 --- /dev/null +++ b/server/Dockerfile @@ -0,0 +1,9 @@ +FROM openjdk:17-jdk-slim + +WORKDIR /app + +COPY /build/libs/*.jar /app/haengdong-0.0.1-SNAPSHOT.jar + +EXPOSE 8080 +ENTRYPOINT ["java"] +CMD ["-Dspring.profiles.active=${SPRING_PROFILES_ACTIVE}", "-Duser.timezone=Asia/Seoul", "-jar", "haengdong-0.0.1-SNAPSHOT.jar"] diff --git a/server/build.gradle b/server/build.gradle new file mode 100644 index 000000000..4229de130 --- /dev/null +++ b/server/build.gradle @@ -0,0 +1,86 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.3.1' + id 'io.spring.dependency-management' version '1.1.5' + id 'org.asciidoctor.jvm.convert' version '3.3.2' +} + +group = 'server' +version = '0.0.1-SNAPSHOT' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +configurations { + compileOnly { + extendsFrom annotationProcessor + } + asciidoctorExt +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'org.springframework.boot:spring-boot-starter-actuator' + + implementation 'io.jsonwebtoken:jjwt:0.9.1' + implementation 'javax.xml.bind:jaxb-api:2.3.1' + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + runtimeOnly 'com.h2database:h2' + runtimeOnly 'com.mysql:mysql-connector-j' + + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + + asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor' + testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc' +} + +ext { + snippetsDir = file('build/generated-snippets') +} + +test { + useJUnitPlatform() + outputs.dir snippetsDir +} + +asciidoctor { + inputs.dir snippetsDir + configurations 'asciidoctorExt' + baseDirFollowsSourceFile() + dependsOn test +} + +tasks.resolveMainClassName { + dependsOn 'copyApiDocuments' +} + +tasks.register('copyApiDocuments', Copy) { + dependsOn asciidoctor + from file("build/docs/asciidoc") + into file("build/resources/main/static/docs") +} + +bootJar { + dependsOn copyApiDocuments +} + +jar { + enabled = false +} + +build { + dependsOn copyApiDocuments +} diff --git a/server/docs/24-08-04-erd.sql b/server/docs/24-08-04-erd.sql new file mode 100644 index 000000000..ae2fbc4a5 --- /dev/null +++ b/server/docs/24-08-04-erd.sql @@ -0,0 +1,65 @@ +-- Create tables +CREATE TABLE action +( + event_id BIGINT, + id BIGINT AUTO_INCREMENT, + sequence BIGINT, + PRIMARY KEY (id) +); + +CREATE TABLE bill_action +( + action_id BIGINT UNIQUE, + id BIGINT AUTO_INCREMENT, + price BIGINT, + title VARCHAR(30), + PRIMARY KEY (id) +); + +CREATE TABLE event +( + id BIGINT AUTO_INCREMENT, + name VARCHAR(255), + token VARCHAR(255), + PRIMARY KEY (id) +); + +CREATE TABLE event_step +( + event_id BIGINT, + id BIGINT AUTO_INCREMENT, + sequence BIGINT, + name VARCHAR(255), + PRIMARY KEY (id) +); + +CREATE TABLE member_action +( + action_id BIGINT UNIQUE, + id BIGINT AUTO_INCREMENT, + member_group_id BIGINT, + member_name VARCHAR(255), + status ENUM('IN', 'OUT'), + PRIMARY KEY (id) +); + +-- Add foreign key constraints +ALTER TABLE action + ADD CONSTRAINT FKgf0qmub9va1xbe44nehny31yw + FOREIGN KEY (event_id) + REFERENCES event (id); + +ALTER TABLE bill_action + ADD CONSTRAINT FK54tx517tp0ry6453olkply4us + FOREIGN KEY (action_id) + REFERENCES action (id); + +ALTER TABLE event_step + ADD CONSTRAINT FKe3rkib91cvl0x5w9wqkshmn81 + FOREIGN KEY (event_id) + REFERENCES event (id); + +ALTER TABLE member_action + ADD CONSTRAINT FK5jna51dn8fs2ir52l4uwn517u + FOREIGN KEY (action_id) + REFERENCES action (id); diff --git a/server/docs/24-08-04-erd.svg b/server/docs/24-08-04-erd.svg new file mode 100644 index 000000000..5a4bac225 --- /dev/null +++ b/server/docs/24-08-04-erd.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Do not edit this file with editors other than draw.io --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1993px" height="1581px" viewBox="-0.5 -0.5 1993 1581" content="<mxfile host="app.diagrams.net" modified="2024-07-25T04:17:06.208Z" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36" etag="gR5VLfYLO6MRu5dHcV28" version="24.7.3" type="github"> <diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1"> <mxGraphModel dx="2380" dy="2150" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0"> <root> <mxCell id="WIyWlLk6GJQsqaUBKTNV-0" /> <mxCell id="WIyWlLk6GJQsqaUBKTNV-1" parent="WIyWlLk6GJQsqaUBKTNV-0" /> <mxCell id="8gZzuRhjrYuwNxX9kY4q-98" value="" style="rounded=0;whiteSpace=wrap;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="-442" y="-590" width="1992" height="1580" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-47" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;startArrow=ERone;startFill=0;endArrow=ERzeroToMany;endFill=0;dashed=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="8gZzuRhjrYuwNxX9kY4q-0" target="8gZzuRhjrYuwNxX9kY4q-37" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-66" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;startArrow=ERone;startFill=0;endArrow=ERzeroToMany;endFill=0;dashed=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="8gZzuRhjrYuwNxX9kY4q-0" target="8gZzuRhjrYuwNxX9kY4q-56" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-0" value="Event" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="40" y="40" width="280" height="120" as="geometry"> <mxRectangle x="480" y="530" width="70" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-1" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="8gZzuRhjrYuwNxX9kY4q-0" vertex="1"> <mxGeometry y="30" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-2" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-1" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-3" value="event_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-1" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-137" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-1" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-7" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-0" vertex="1"> <mxGeometry y="60" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-8" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-7" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-9" value="token" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-7" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-138" value="varchar(20)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-7" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-4" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-0" vertex="1"> <mxGeometry y="90" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-5" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-4" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-6" value="name" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-4" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-139" value="varchar(255)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-4" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-37" value="Event_Step" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="40" y="240" width="280" height="150" as="geometry"> <mxRectangle x="480" y="530" width="70" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-38" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="8gZzuRhjrYuwNxX9kY4q-37" vertex="1"> <mxGeometry y="30" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-39" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-38" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-40" value="event_step_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-38" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-143" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-38" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-41" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-37" vertex="1"> <mxGeometry y="60" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-42" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-41" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-43" value="name" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-41" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-144" value="varchar(30)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-41" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-44" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-37" vertex="1"> <mxGeometry y="90" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-45" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-44" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-46" value="sequence" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-44" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-145" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-44" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-48" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-37" vertex="1"> <mxGeometry y="120" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-49" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-48" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-50" value="event_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-48" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-146" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-48" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-77" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;startArrow=ERone;startFill=0;endArrow=ERone;endFill=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="8gZzuRhjrYuwNxX9kY4q-56" target="8gZzuRhjrYuwNxX9kY4q-67" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-91" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;startArrow=ERone;startFill=0;endArrow=ERone;endFill=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="8gZzuRhjrYuwNxX9kY4q-56" target="8gZzuRhjrYuwNxX9kY4q-81" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-56" value="Action" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="414" y="40" width="280" height="120" as="geometry"> <mxRectangle x="480" y="530" width="70" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-57" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="8gZzuRhjrYuwNxX9kY4q-56" vertex="1"> <mxGeometry y="30" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-58" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-57" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-59" value="action_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-57" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-140" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-57" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-60" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-56" vertex="1"> <mxGeometry y="60" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-61" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-60" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-62" value="sequence" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-60" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-141" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-60" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-63" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-56" vertex="1"> <mxGeometry y="90" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-64" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-63" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-65" value="event_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-63" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-142" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-63" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-67" value="Bill_Action" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="414" y="240" width="280" height="150" as="geometry"> <mxRectangle x="480" y="530" width="70" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-68" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="8gZzuRhjrYuwNxX9kY4q-67" vertex="1"> <mxGeometry y="30" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-69" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-68" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-70" value="bill_action_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-68" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-147" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-68" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-71" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-67" vertex="1"> <mxGeometry y="60" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-72" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-71" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-73" value="title" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-71" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-148" value="varchar(30)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-71" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-78" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-67" vertex="1"> <mxGeometry y="90" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-79" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-78" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-80" value="price" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-78" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-149" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-78" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-74" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-67" vertex="1"> <mxGeometry y="120" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-75" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-74" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-76" value="action_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-74" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-150" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-74" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-81" value="Member_Action" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="790" y="40" width="280" height="180" as="geometry"> <mxRectangle x="480" y="530" width="70" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-82" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="8gZzuRhjrYuwNxX9kY4q-81" vertex="1"> <mxGeometry y="30" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-83" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-82" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-84" value="member_action_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-82" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-151" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-82" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-85" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-81" vertex="1"> <mxGeometry y="60" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-86" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-85" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-87" value="member_name" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-85" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-152" value="varchar(20)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-85" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-92" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-81" vertex="1"> <mxGeometry y="90" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-93" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-92" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-94" value="status" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-92" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-153" value="varchar(10)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-92" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-95" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-81" vertex="1"> <mxGeometry y="120" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-96" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-95" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-97" value="member_group_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-95" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-154" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-95" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-88" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-81" vertex="1"> <mxGeometry y="150" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-89" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-88" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-90" value="action_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-88" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-155" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-88" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> </root> </mxGraphModel> </diagram> </mxfile> " resource="https://app.diagrams.net/?src=about#Hkunsanglee%2Fcafekiosk-study%2Fmain%2Fsrc%2Fmain%2Fresources%2Fexample2.svg#%7B%22pageId%22%3A%22C5RBs43oDa-KdzZeNtuy%22%7D"><defs/><g><g data-cell-id="WIyWlLk6GJQsqaUBKTNV-0"><g data-cell-id="WIyWlLk6GJQsqaUBKTNV-1"><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-98"><g><rect x="0" y="0" width="1992" height="1580" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-47"><g><path d="M 622 750 L 622 814.5" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 626 754 L 618 754" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="622" cy="818" rx="3" ry="3" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 626 830 L 622 822 L 618 830 M 622 822 L 622 830" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-66"><g><path d="M 762 690 L 840.5 690" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 766 686 L 766 694" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="844" cy="690" rx="3" ry="3" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 856 686 L 848 690 L 856 694 M 848 690 L 856 690" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-0"><g><path d="M 482 660 L 482 630 L 762 630 L 762 660" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 482 660 L 482 750 L 762 750 L 762 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 482 660 L 762 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 512 660 L 512 690 L 512 720 L 512 750" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 632 660 L 632 690 L 632 720 L 632 750" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 645px; margin-left: 622px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: nowrap;">Event</div></div></div></foreignObject><text x="622" y="649" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">Event</text></switch></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-1"><g><path d="M 482 660 M 762 660 M 762 690 L 482 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-2"><g><rect x="482" y="660" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 660 M 512 660 M 512 690 M 482 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 675px; margin-left: 483px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">PK</div></div></div></foreignObject><text x="497" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">PK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-3"><g><rect x="512" y="660" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 660 M 632 660 M 632 690 M 512 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 675px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">event_id</div></div></div></foreignObject><text x="520" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">event_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-137"><g><rect x="632" y="660" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 660 M 762 660 M 762 690 M 632 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 675px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="640" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-7"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-8"><g><rect x="482" y="690" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 690 M 512 690 M 512 720 M 482 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-9"><g><rect x="512" y="690" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 690 M 632 690 M 632 720 M 512 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 705px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">token</div></div></div></foreignObject><text x="520" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">token</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-138"><g><rect x="632" y="690" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 690 M 762 690 M 762 720 M 632 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 705px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(20)</div></div></div></foreignObject><text x="640" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(20)</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-4"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-5"><g><rect x="482" y="720" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 720 M 512 720 M 512 750 M 482 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-6"><g><rect x="512" y="720" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 720 M 632 720 M 632 750 M 512 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 735px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">name</div></div></div></foreignObject><text x="520" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">name</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-139"><g><rect x="632" y="720" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 720 M 762 720 M 762 750 M 632 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 735px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(255)</div></div></div></foreignObject><text x="640" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(255)</text></switch></g></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-37"><g><path d="M 482 860 L 482 830 L 762 830 L 762 860" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 482 860 L 482 980 L 762 980 L 762 860" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 482 860 L 762 860" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 512 860 L 512 890 L 512 920 L 512 950 L 512 980" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 632 860 L 632 890 L 632 920 L 632 950 L 632 980" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 845px; margin-left: 622px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: nowrap;">Event_Step</div></div></div></foreignObject><text x="622" y="849" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">Event_Step</text></switch></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-38"><g><path d="M 482 860 M 762 860 M 762 890 L 482 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-39"><g><rect x="482" y="860" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 860 M 512 860 M 512 890 M 482 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 875px; margin-left: 483px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">PK</div></div></div></foreignObject><text x="497" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">PK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-40"><g><rect x="512" y="860" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 860 M 632 860 M 632 890 M 512 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 875px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">event_step_id</div></div></div></foreignObject><text x="520" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">event_step_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-143"><g><rect x="632" y="860" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 860 M 762 860 M 762 890 M 632 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 875px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="640" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-41"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-42"><g><rect x="482" y="890" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 890 M 512 890 M 512 920 M 482 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-43"><g><rect x="512" y="890" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 890 M 632 890 M 632 920 M 512 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 905px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">name</div></div></div></foreignObject><text x="520" y="909" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">name</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-144"><g><rect x="632" y="890" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 890 M 762 890 M 762 920 M 632 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 905px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(30)</div></div></div></foreignObject><text x="640" y="909" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(30)</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-44"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-45"><g><rect x="482" y="920" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 920 M 512 920 M 512 950 M 482 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-46"><g><rect x="512" y="920" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 920 M 632 920 M 632 950 M 512 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 935px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">sequence</div></div></div></foreignObject><text x="520" y="939" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">sequence</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-145"><g><rect x="632" y="920" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 920 M 762 920 M 762 950 M 632 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 935px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="640" y="939" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-48"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-49"><g><rect x="482" y="950" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 950 M 512 950 M 512 980 M 482 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 965px; margin-left: 483px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FK</div></div></div></foreignObject><text x="497" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">FK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-50"><g><rect x="512" y="950" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 950 M 632 950 M 632 980 M 512 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 965px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">event_id</div></div></div></foreignObject><text x="520" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">event_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-146"><g><rect x="632" y="950" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 950 M 762 950 M 762 980 M 632 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 965px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="640" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-77"><g><path d="M 996 750 L 996 830" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 1000 754 L 992 754" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 992 826 L 1000 826" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-91"><g><path d="M 1136 690 L 1184 690 L 1184 720 L 1232 720" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 1140 686 L 1140 694" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 1228 724 L 1228 716" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-56"><g><path d="M 856 660 L 856 630 L 1136 630 L 1136 660" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 856 660 L 856 750 L 1136 750 L 1136 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 856 660 L 1136 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 886 660 L 886 690 L 886 720 L 886 750" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1006 660 L 1006 690 L 1006 720 L 1006 750" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 645px; margin-left: 996px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: nowrap;">Action</div></div></div></foreignObject><text x="996" y="649" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">Action</text></switch></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-57"><g><path d="M 856 660 M 1136 660 M 1136 690 L 856 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-58"><g><rect x="856" y="660" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 660 M 886 660 M 886 690 M 856 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 675px; margin-left: 857px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">PK</div></div></div></foreignObject><text x="871" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">PK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-59"><g><rect x="886" y="660" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 660 M 1006 660 M 1006 690 M 886 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 675px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">action_id</div></div></div></foreignObject><text x="894" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">action_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-140"><g><rect x="1006" y="660" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 660 M 1136 660 M 1136 690 M 1006 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 675px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-60"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-61"><g><rect x="856" y="690" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 690 M 886 690 M 886 720 M 856 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-62"><g><rect x="886" y="690" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 690 M 1006 690 M 1006 720 M 886 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 705px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">sequence</div></div></div></foreignObject><text x="894" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">sequence</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-141"><g><rect x="1006" y="690" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 690 M 1136 690 M 1136 720 M 1006 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 705px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-63"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-64"><g><rect x="856" y="720" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 720 M 886 720 M 886 750 M 856 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 735px; margin-left: 857px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FK</div></div></div></foreignObject><text x="871" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">FK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-65"><g><rect x="886" y="720" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 720 M 1006 720 M 1006 750 M 886 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 735px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">event_id</div></div></div></foreignObject><text x="894" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">event_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-142"><g><rect x="1006" y="720" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 720 M 1136 720 M 1136 750 M 1006 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 735px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-67"><g><path d="M 856 860 L 856 830 L 1136 830 L 1136 860" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 856 860 L 856 980 L 1136 980 L 1136 860" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 856 860 L 1136 860" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 886 860 L 886 890 L 886 920 L 886 950 L 886 980" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1006 860 L 1006 890 L 1006 920 L 1006 950 L 1006 980" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 845px; margin-left: 996px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: nowrap;">Bill_Action</div></div></div></foreignObject><text x="996" y="849" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">Bill_Action</text></switch></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-68"><g><path d="M 856 860 M 1136 860 M 1136 890 L 856 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-69"><g><rect x="856" y="860" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 860 M 886 860 M 886 890 M 856 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 875px; margin-left: 857px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">PK</div></div></div></foreignObject><text x="871" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">PK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-70"><g><rect x="886" y="860" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 860 M 1006 860 M 1006 890 M 886 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 875px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bill_action_id</div></div></div></foreignObject><text x="894" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bill_action_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-147"><g><rect x="1006" y="860" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 860 M 1136 860 M 1136 890 M 1006 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 875px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-71"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-72"><g><rect x="856" y="890" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 890 M 886 890 M 886 920 M 856 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-73"><g><rect x="886" y="890" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 890 M 1006 890 M 1006 920 M 886 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 905px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">title</div></div></div></foreignObject><text x="894" y="909" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">title</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-148"><g><rect x="1006" y="890" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 890 M 1136 890 M 1136 920 M 1006 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 905px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(30)</div></div></div></foreignObject><text x="1014" y="909" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(30)</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-78"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-79"><g><rect x="856" y="920" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 920 M 886 920 M 886 950 M 856 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-80"><g><rect x="886" y="920" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 920 M 1006 920 M 1006 950 M 886 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 935px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">price</div></div></div></foreignObject><text x="894" y="939" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">price</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-149"><g><rect x="1006" y="920" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 920 M 1136 920 M 1136 950 M 1006 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 935px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="939" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-74"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-75"><g><rect x="856" y="950" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 950 M 886 950 M 886 980 M 856 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 965px; margin-left: 857px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FK</div></div></div></foreignObject><text x="871" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">FK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-76"><g><rect x="886" y="950" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 950 M 1006 950 M 1006 980 M 886 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 965px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">action_id</div></div></div></foreignObject><text x="894" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">action_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-150"><g><rect x="1006" y="950" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 950 M 1136 950 M 1136 980 M 1006 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 965px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-81"><g><path d="M 1232 660 L 1232 630 L 1512 630 L 1512 660" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 1232 660 L 1232 810 L 1512 810 L 1512 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1232 660 L 1512 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1262 660 L 1262 690 L 1262 720 L 1262 750 L 1262 780 L 1262 810" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1382 660 L 1382 690 L 1382 720 L 1382 750 L 1382 780 L 1382 810" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 645px; margin-left: 1372px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: nowrap;">Member_Action</div></div></div></foreignObject><text x="1372" y="649" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">Member_Action</text></switch></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-82"><g><path d="M 1232 660 M 1512 660 M 1512 690 L 1232 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-83"><g><rect x="1232" y="660" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1232 660 M 1262 660 M 1262 690 M 1232 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 675px; margin-left: 1233px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">PK</div></div></div></foreignObject><text x="1247" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">PK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-84"><g><rect x="1262" y="660" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1262 660 M 1382 660 M 1382 690 M 1262 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 675px; margin-left: 1270px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">member_action_id</div></div></div></foreignObject><text x="1270" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">member_action_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-151"><g><rect x="1382" y="660" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1382 660 M 1512 660 M 1512 690 M 1382 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 675px; margin-left: 1390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1390" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-85"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-86"><g><rect x="1232" y="690" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1232 690 M 1262 690 M 1262 720 M 1232 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-87"><g><rect x="1262" y="690" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1262 690 M 1382 690 M 1382 720 M 1262 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 705px; margin-left: 1270px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">member_name</div></div></div></foreignObject><text x="1270" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">member_name</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-152"><g><rect x="1382" y="690" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1382 690 M 1512 690 M 1512 720 M 1382 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 705px; margin-left: 1390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(20)</div></div></div></foreignObject><text x="1390" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(20)</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-92"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-93"><g><rect x="1232" y="720" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1232 720 M 1262 720 M 1262 750 M 1232 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-94"><g><rect x="1262" y="720" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1262 720 M 1382 720 M 1382 750 M 1262 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 735px; margin-left: 1270px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">status</div></div></div></foreignObject><text x="1270" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">status</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-153"><g><rect x="1382" y="720" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1382 720 M 1512 720 M 1512 750 M 1382 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 735px; margin-left: 1390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(10)</div></div></div></foreignObject><text x="1390" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(10)</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-95"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-96"><g><rect x="1232" y="750" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1232 750 M 1262 750 M 1262 780 M 1232 780" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-97"><g><rect x="1262" y="750" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1262 750 M 1382 750 M 1382 780 M 1262 780" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 765px; margin-left: 1270px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">member_group_id</div></div></div></foreignObject><text x="1270" y="769" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">member_group_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-154"><g><rect x="1382" y="750" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1382 750 M 1512 750 M 1512 780 M 1382 780" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 765px; margin-left: 1390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1390" y="769" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-88"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-89"><g><rect x="1232" y="780" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1232 780 M 1262 780 M 1262 810 M 1232 810" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 795px; margin-left: 1233px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FK</div></div></div></foreignObject><text x="1247" y="799" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">FK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-90"><g><rect x="1262" y="780" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1262 780 M 1382 780 M 1382 810 M 1262 810" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 795px; margin-left: 1270px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">action_id</div></div></div></foreignObject><text x="1270" y="799" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">action_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-155"><g><rect x="1382" y="780" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1382 780 M 1512 780 M 1512 810 M 1382 810" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 795px; margin-left: 1390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1390" y="799" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g></g></g></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg> \ No newline at end of file diff --git a/server/gradle/wrapper/gradle-wrapper.jar b/server/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..e6441136f3d4ba8a0da8d277868979cfbc8ad796 GIT binary patch literal 43453 zcma&N1CXTcmMvW9vTb(Rwr$&4wr$(C?dmSu>@vG-+vuvg^_??!{yS%8zW-#zn-LkA z5&1^$^{lnmUON?}LBF8_K|(?T0Ra(xUH{($5eN!MR#ZihR#HxkUPe+_R8Cn`RRs(P z_^*#_XlXmGv7!4;*Y%p4nw?{bNp@UZHv1?Um8r6)Fei3p@ClJn0ECfg1hkeuUU@Or zDaPa;U3fE=3L}DooL;8f;P0ipPt0Z~9P0)lbStMS)ag54=uL9ia-Lm3nh|@(Y?B`; zx_#arJIpXH!U{fbCbI^17}6Ri*H<>OLR%c|^mh8+)*h~K8Z<V--Q23O4&HBVn~<)q zmUaP7+TjluBM%#s1Ki#^GurGElkc7{cc6Skz+1nDVk%wAAQYx1^*wA%KSY>!9)DPf zR2h?lbDZQ`p9P;&DQ4F0sur@TMa!Y}S8irn(%d-gi0*WxxCSk*A?3lGh=gcYN?FGl z7D=Js!i~0=u3rox^e<cs4tSN~YA?c-d185$YFNA$Eq1&U{wh#b^OveuKoBPy0oYZ4 zAY2?B=x8yX9}pVM=cLrvugywt!e@Y3lH)i?7fvT*a`O;c)CJQ>O3i@$0=n{K1lPNU zwmfjRVmLOCRfe=seV&P*1Iq=^i`502keY8Uy-WNPwVNNtJFx?IwA<BCEY82WDKJP< zB^CxjFxi=mg*OyI?K3GoDfk;?-K<Z#JoxhYNeEUf896)l%7gL``44}zn)7|Rf;)SC z_EfJr4I+3i(GiHN`R+vHqf}1wXtH?65<wKlxV1BU(#3XgtH<$Fir3S(7QeRA3)u89 zID&66K{&mq$DsB}s&o?H60{cskfh*hvn8hQW#~Q!qM04QtZvx3JEpqeKWE6|+OZW= z(LB7}flr|t7va%>yR<KG!FYzS$bs7qXcpM&wV@~>PZo2<wCq%CszVO$mosTTuv*Mz zOLoi?e^7B~xS22~QW8Rmnt{(AtL<HGi<_P9`0pH;3)@S9Eg`gt2X<om7C^q}pKX|* zTy3X{nOr-xyt4=Qx1IjrzGb!_SyAv^SZcf;air&-;Ua+)5k0z=#R7@UW%)3oEjGA| zZ#DE3px@h1k7w%|4rVIO=0Aid2A%?nBZrupg^_z5J-$$YKeDZ&q8+k7zccb<dc4D; zz}+UYkl_eUNL3PW+reZ6UUB}=sHp~$z%Q}gZ-#ow+ffQIj|A3`B9LO*6%t@)0PV!x ziJ=9fw_>Wo1+S(xF37LJZ~%i)kpFQ3Fw=mXfd@>%+)RpYQLnr}B~~zoof(JVm^^&f zxKV^+3D3$A1G;qh4gPVjhrC8e(VYUHv#dy^)(RoUFM?o%W-EHxufuWf(l*@-l+7vt z=l`qmR56K~F|v<^Pd*p~1_y^P0P^aPC##d8+HqX4IR1gu+7w#~TBFphJxF)T$2WEa zxa?H&6=Qe7d(#tha?_1uQys2KtHQ{)Qco)qwGjrdNL7thd^G5i8Os)CHqc>iOidS} z%nFEDdm=GXBw=yXe1W-ShHHFb?Cc70+$W~z_+}nAoHFYI1MV1wZegw*0y^tC*s%3h zhD3tN8b=Gv&rj}!SUM6|ajSPp*58KR7MPpI{oAJCtY~JECm)*m_x>AZEu>DFgUcby z1Qaw8lU4jZpQ_$;*7RME+gq1Ky<fW-rh4ehZ;%u960Gt5OF)<y$00S=6tVE=%Pt~( z!&BP&2I%`@>SGG#Wql>aL~k9tLrSO()LWn*q&YxHE<sT^`N@Q|)S3y<ZACaLXO56z zncP$~M5K!npWqz?)C50MMw=XqFtDO!3JHI*t-^8Ga&lGPHX2F0pIGdZ3w5ewE+{kf z-&Ygi?@-h(ADD|ljIBw%VHHf1xuQ~}IeIQ5JqlA4#*Nlvd`IfDYzFa?PB=RCcFpZ4 z|HFmPZM=;^DQ_z<IPz$$+yG(H4803QQAA7vQF7;_gv|AD1bH*R-CP3f<<utDpH)Ht zI@{uO12adp{;132YoKPx?C9{&;MtHdHb*0F0;Z~D42}#*l+WD2u?r>uzmwd1?aAtI zBJ>P=&$=l1efe1CDU;`Fd+_;&wI07?V0aAIgc(<VS*?#8Zt!w88FJrjasA1!6>!{a z0Jg6Y=inXc3^n!U0Atk`iCFIQooHqcWhO(qrieUOW8X(x?(RD}iYDLMjSwffH2~tB z)oDgNBLB^AJBM1M^c5HdRx6fBfka`(LD-qrlh5jqH~);#nw|iyp)()xVYak3;Ybik z0j`(+69aK*B>)e_p%=wu8XC&9e{AO4c~O1U`5X9}?0mrd*m$_EUek{R?DNSh(=br# z#Q61gBzEpmy`$pA<eVn3dnmk^xq`=o2)~2c0ywsuTQsC?1WZZehsJYfK@LQ>*6!87 zSDD+=@fTY7<4A?GLqpA?Pb2z$pbCc4B4zL{BeZ?F-8`s$?>*lXXtn*NC61>|*w7J* z$?!iB{6R-0=KFmyp1nnEmLsA-H0a6l+1uaH^g%c(p{iT&YFrbQ$&PRb8Up#X3@Zsk zD^^&LK~111%cqlP%!_gFNa^dTYT?rhkGl}5=fL{a`UViaXWI$k-UcHJwmaH1s=S$4 z%4)PdWJX;hh5UoK?6aWoyLxX&NhNRqKam7tcOkLh{%j3K^4Mgx1@i|Pi&}<^5>hs5 zm8?uOS>%)NzT(%PjVPGa?X%`N2TQCKbeH2l;cTnHiHppPSJ<7y-yEIiC!P*ikl&!B z%+?>VttCOQM@ShFguHVjxX^?mHX^hSaO_;pnyh^v9EumqSZTi+#f&_Vaija0Q-e*| z7ulQj6Fs*bbmsWp{`auM04gGwsYYdNNZcg|ph0OgD>7O}Asn7^<IivRZw`Wa$`V6) zgX@^QL9j}-Od{q5<J*k0+1U=R5+PCYj(U}4VpX+BjfI~+dttS?HJ6uZSGH#H-twTo zaptG40+PAc$fs*zLFkOfGfc+xGs<T?rLGIA%SU7c%jh!E1SNN~*-`ccW8wo4gv2Sj zhify^C(ygi)uGwqXDLqVbH>Z=eI>`$2*v78;sj-}oMoEj&@)9+ycEOo92xSyY344^ z11Hb8^kdOvbf^GNAK++bYioknrpdN>+u8R?JxG=!2Kd9r=YWCOJYXYuM0cOq^FhEd zBg2puKy__7VT3-r*dG4c62Wgxi52EMCQ`bKgf*#*ou(D4-ZN$+m<X+=`m<r!lO%3T zMp}MJd(WDoQ2&6(LClZxpv<vZPPM3Ngkye2VhB=i|B12g5ouw(%`gbWtRq8~sU|o* z$kQ8Jb~6&{ak;r$7@?#t*q9RfAOj=^uAf1z5Y8`N%M`oM@?!~VqN{g%-u$XR1u1Im zGE&AzFpIcER(5jtCPR%RZ)!+|*rU~jZBiOKdqYjO(%yK3Lz;{##(@QEVo>g&7$u!! z-^<eVk1WtrWdvAzoBMHoB$s2RXJCv}%muyVFFJ``?>+Z%;-3IDwqZ|K=ah85OLwkO zKxNBh+4QHh)u9D?MFtpbl)<T1$eOrb4-+U|WDC2BesgFRlgt`klbeQ^1S`7`r+uZ8 zH&U=geA}Si;CUcKvBA&^@<o1GQ7`{1Y(cCHZv|73JIJOvVwLOMZP%Q|)y@^j2e<+z zWVo=#FL!4XNKS~-_1`gw*qi$0j6P7ym_LTvG>us}9+V!D%w9jfAMYEb>%$A;u)rrI zuBudh;5PN}_6J_}l55P3l_)&RMlH{m!)ai-i$g)&*M`eN$XQMw{v^r@-125^RRCF0 z^2>|DxhQw(mtNEI2Kj(;<s2pnue6O@?^QaAp;Ze6z9nX*w}4h7342+0lU$@;Knnve zqqY2Ci=`)@>KblC7x=JlK$@78`O~>V!`|1Lm-^JR$-5pUANAnb(5}B}JGjBsliK4& zk6y(;$e&h)lh2)L=bvZKbvh@>vLlreBdH8No2>$#%_Wp1U0N7Ank!6$dFSi#xzh|( zRi{U<eziQYNZ-=4ReK3@^LFvNQI~(Pdvp+X@J@g#bd~m0wFc+sW3Xf5tyA3xKp;T3 zy14<o-`F}$ET-DQ;B;yNy?d>w%-4W!{IXZ)fWx@XX6;&(m_F%c6~X8hx=BN1&q}*( zoaNjWabE{oUPb!Bt$eyd#$5j9rItB-h*5JiNi(v^e|XKAj*8(k<5-2$&ZBR5fF|JA z9&m4fbzNQnAU}r8ab>fFV%J0z5awe#UZ|bz?Ur)U9bCIKWEzi2%A+5CLqh?}K4JHi z4vtM;+u<SJ)DEVF_yZnTw01M`(s#^BNx+c|MQ6ogb50Jjul0L;!#OmrYCs)iE)7(t z?%I~O!zVNt#Bf3#O2WXsGz!B}&s@MfyDeaoqqf=GELN3g$+DA`&&GKy(`Ya~A@6vK zn|WZ-+tB`DH^+SjI&K3KekF%-QIP%R{F)inWc~@cEO-=3Or<lm9g9}|`|ky#v{5*; zKA5d<ecC{<o9p<U4UUK$m|+q#@(>PsVz{Lfr;78W78gC;z*yTch~4YkLr&m-7%-xc ztw6Mh2<b07B|^BQBjvq{FXx?kyJ);`+G*=&9PMD`1uf<{+pNnnsIQx~kaB?*5<-7a zqY)GyF_w$>d>_iO<o;tRi5=dcnU&wcur@4T5Z=-$xFUEsp-yX${|jSF|HMDPq3?MS zw;p9zjR`yYJOfJZsK~C-S=JQ?nX{z_y@06JFIpheAo-rOG|5&Gxv)%95gpu@ESfi| z7Auc&hjVL;&81Pc#L`^d9gJb`wEtLVH8q|h{>*$Rd8(-Cr1_V8EO1f*^@wRoSozS) zy1UoC@pruAaC8Z_7~_w4Q6n*&B0AjOmMWa;s<dwKr_&w<X$Z*rmLmKUI3S>Iav&gu z|J5&|{=a@vR!~k-OjKEgPFCzcJ>#A1uL&7xTDn;{X<DkOU(-L87#5hf4{m?aj!I6- zPEt$K07IXK8mI0TYf-jhke2QjQw3v?qN5h0-#Fel0)Krq1f)#^AFsfd|K$I={`Xs9 z{JIr8M>BdeM}V=l3B8fE1--DHjSaxoSjNKEM9|U9#m2<eS=8Og#NOG$&X&%|8sOyg zpZ6&%KPd&uh?v{hRMVvQjUL}gY3)Mk3{XQXF{><3>n{Iuo`r3UZp;>GkT2YBNAh|b z^jTq-hJp(ebZh#Lk8hVBP%qXwv-@vbvoREX$TqRGTgEi$%_F9tZES@z8Bx}$#5eeG zk^UsLBH{bc2VBW)*EdS({yw=?qmevwi?BL6*=12k9zM5gJv1>y#ML4!)iiPzVaH9% zgSImetD@dam~e>{LvVh!phhzpW+iFvWpGT#CVE5TQ40n%F|p(sP5mXxna+Ev7PDwA zamaV4m*^~*xV+&p;W749xhb_X=$|LD;FHuB&JL5?*Y2-oIT(wYY2;73<^#46S~Gx| z^cez%V7x$81}UWqS13Gz80379Rj;6~WdiXWOSsdmzY39L;Hg3MH43o*y8ib<ko|2T z<o~B%-$Y4Q9z_t97c`{g0veSfFt63Osbpe2Osn@<=nrAVk_JfMGt&lMGw9leshc#5 z*hkn0u>NBBH`(av4|u;YPq%{R;IuYow<+GEsf@R?=@tT@!}?#>zIIn0CoyV!hq3mw zHj>OOjfJM3F{RG#6ujzo?y32m^tgSXf@v=J$ELdJ+=5j|=F-~hP$G&}tDZsZE?5rX ztGj`!S>)CFmdkccxM9eGIcGnS2AfK#gXwj%esuIBNJQP1WV~b~+D7PJTmWGTSDrR` zEAu4B8l>NPuhsk5a`rReSya2nfV<T&F{)-N{)9$`9a!^D!-03RDN<TPH!aW46TC4L z>1EK01+G!x8aBdTs3Io$u5!6n6KX%uv@DxAp3F@{4UYg4SWJtQ-W~0MDb|j-$lwVn znAm*Pl!?Ps&3wO=R115RWKb*JKoexo*)uhhHBncEDMSVa_PyA>k{Zm2(wMQ(5NM3# z)jkza|GoWEQo4^s*wE(gHz?Xsg4`}HUAcs42cM1-qq_=+=!Gk^y710j=66(cSWqUe zklbm8+zB_<cF$~mH3zum`PN7rn^cr1XvcjzxFO{ms_482AyMFYi+#o7!*vecrNhft z48z<2q#fIw=ce!MXuptfT4+M8FP&|QfB3H@2)dceSR<*e5@hq<#7<$5tC^!RO8Zi< zd_Wl!>syQv5A2rj!Vbw8;|$@C!vfNmNV!yJ<MblqN@23-5g1<aeoul%Um5K((_QY} ze%_@BuNzay69}2PhmC<;m}2=FevDzrp!V!u4u|#h@B=rfKt+v!U`0k7>IWDQ>{+2x zKjuFX`~~HKG~^6h5FntRpnnHt=D&rq0>IJ9#F0eM)Y-)GpRjiN7gkA8wvnG#K=q{q z9dBn8_~wm4J<3J_vl|9H{7q6u2A!cW{bp#r*-f{gOV^e=8S{nc1DxMHFwuM$;aVI^ zz6A*}m8N-&x8;aunp1w7_vtB*pa+OYBw=TMc6Q<xVqo{NJ3h9-a)s5XuYMqZ=Y{7{ z$O63J`)FM-y*mko#!-UBa!3~eYtX1hjRQY2jMxAx=q5uKNm#uaKIak>K=mbA-|Cf* zvyh8D4LRJImooUaSb7t*fVfih<97Gf@VE0|z>NcBwBQze);Rh!k3K_sfunToZY;f2 z^HmC4KjHRVg+eKYj;PRN^|E0>Gj_zagfRbrki68I^#~6-HaHg3BUW%<xsJq4AotN+ zH6twFV=)FlAbs*F6vGws^==x5Tl0AIbcP{&2yxB=)*u+bvK^L6$Vp}U2{9nj{bK~d zee7tC)@DR<dI`D%cA(%7M9Ui3a)^iG?m=oJO0E^``<|5il2sf1fZHvy=D@e0<I)<l zI!|d{`X3u}lz2(4Vn>+clM1<yhZZgPANro5CwhUb>xQEdPYt_g<2K+z!$>*$9nQ>; zf9Bei{?zY^-e{q_*|W#2rJG`2fy@{%6u0i_VEWTq$*(ZN37|8lFFFt)nCG({r!q#9 z5VK_kkS<W$zJN%xs9<lngf<utn=i|I;bCdr-Lr<EzK)tkE-pYh-fc0wqKz?&U8TTN zh_eAdl<>J3?zOH)OezMT{!YkCuSSn!<oaxO4?NS?VufjhPn>K#-Rhl$uUM(bq*jY? zi1xbMVthJ`E>d>(f3)~fozjg^@eheMF6<)I`oeJYx4*+M&%c9VArn(OM-wp%M<-`x z7sLP1&3^%Nld9Dhm@$3f2}87!quhI<BVn6Upp<cc;cU|)&2W%nk!Ak8tXK8aT!m*5 z^9zmeeS|PCG$hgM&Uh}0wp+#$jK3YCwOT&nx$??=a@_oQemQ~hS6nx6fB5r~bFSPp z`alXuTYys4S5dCK)KDGR@7`I-JV^ewQ_BGM^o>@nwd@3~fZl_3LYW-B?Ia>ui`ELg z&Qfe!7<FViITCBP{rA>m6ze=mZ<W0bN&bq-0D3>`Ia9$z|ARSw|IdMpooY4YiPN8K z4B(ts3p%<w%rbophph+BzYj>2i(Td=<hfIaF6Ll8+9!48Ti=xpXB{FgJbk;>tgEHX z0UQ_>URBtG+-?0E;E7Ld^dyZ;jjw0}XZ(}-QzC6+NN=40oDb2^v!L1g9xRvE#@IBR zO!b-2N7wVfLV;mhEaXQ9XAU+>=XVA6f&T4Z-@AX!leJ8obP^P^wP0aICND?~w&N<u ztispy>ykJ#54x3_@r7IDMdRNy4Hh;h*!u(Ol(#0bJdwEo$5437-UBjQ+j=Ic>Q2z` zJNDf0yO6@mr6y1#n3)s(W|$iE_i8r@Gd@!DWD<Q)gT}bxTg_YpJQ5s|m8}+B)KBN6 zYnlzh>qZ7J&~gAm1#~maIGJ<sH@F<m!Fuh_fvrMbcDJNJ5~Yg;LF}NFN}&Y&LL76S zv)~8W2?_rx`P;4LB-=JqsI{I~4U8DnSSIHWU2rHf%vWsA2-d=78An8z4q|lvgQ2iB zhUUI!H+|C+_qp(Tjzu5usOu}cEoivZK&XA==sh0cD|Eg7eERXx?KwHI=}A9S_rx8S zd)VLh_s!Juqi^!0xv7jH)UdSkEY~N|;QMWvs;HN`dMsdK=Dw2mtAHHcK8_+kS%a_V zGgeQoaMM>1sls^gxL9LLG_Nh<XXk<>U!pTGty!TbhzQnu)I*S^54U6Yu%ZeCg`R>Q zhBv$n5j<?~h)Y%y=zErI?{tl!(JWSDXxco7X8WI-6K;9Z-h&~kIv?$!6<k(g(xee? z53>0v%O_j{QYWG!R9W?5_b&67KB$t}&e2LdMvd(PxN6Ir!H4>PNlerpBL>Zvyy!yw z-SOo8caEpDt(}|gKPBd$qND5#a5nju^O>V&;f890?yEOfkSG^HQVmEbM3Ugzu+UtH zC(INPDdraBN?P%kE;*Ae%Wto&sgw(crfZ#Qy(<4nk;S|hD3j{IQRI6Yq|f^basLY; z-HB&Je%Gg}Jt@={_C{L$!RM;$$|<j7k-g{75e!h)4SlFvEZ*AkqrJI;EWu$Zx+OwM zm{5Yk>iD6vu#3w?v?*;&()uB|I-XqEKqZPS!reW9JkLewLb!70T7n`i!gNtb1%vN- zySZj{8-1>6E%H&=V}LM#xmt`J3XQoaD|@XygXjdZ1+P77-=;=eYpoEQ01B@L*a(uW zrZeZz?HJsw_4g0vhUgkg@VF8<-X$B8pOqCuWAl28uB|@r`19DTUQQsb^pfqB6QtiT z*`_UZ`fT}vtUY#%sq2{rchyfu*pCg;uec2$-$N_xgjZcoumE5vSI{+s@iLWoz^Mf; zuI8kDP{!XY6OP~q5}%1&L}CtfH^N<3o4L@J@zg1-mt{9L`s^z$Vgb|mr{@WiwAqKg zp#t-lhrU>F8o0s1q_9y`gQNf~Vb!F%70f}$>i7o4ho<sjDlFD=G`r<7$U?bJN+x5S z@0&tQ=-XO1uDq(HCa$X)-l<u1!s<!W`30F78UcZaZKc8)G0af1Dsh%OOWh5)q+Q+n zySBnE+3;9^#)U#Gq);&Cu=mtjNpsS~S0yjE@m4{Kq525G&cO_+b-_B$LeXWt_@XTq z`)(;=^RDS@oh5dPjKyGAP?-Dbh507E5zZ=D2_C*6s^HXiA)B3f=65_M+rC&rMIUP6 zi4@u>$`uciNf=xgJ>&!gSt0g;M>*x4-`U)ysFW&Vs^Vk6m%?iuWU+o&m(2Jm26<Ea z?or_^bK_`R)hBTfrBqA3Y^o7$K~Nzo)sh-vT%yWcc1I5wF1nkvk%!X_Vl_MK1IHC= zt}Dt+sOmg0sH-?}kqNB|M_}ZXui7H;?;?xCCSIPSHh8@h^K8WU5X(!3W|>Y(3%TL; zA7T)BP{WS!&xmxNw%J=$MPfn(9*^*TV;$JwRy8Zl*yUZi8jWYF>==j~&S|Xinsb%c z2?B+kpet*muEW7@AzjBA^wAJBY8i|#C{WtO_or&Nj2{=6JTTX05}|H>N2B|Wf!*3_ z7hW*j6p3TvpghEc6-wufFiY!%-GvOx*bZrhZu+7?iSrZL5q9}igiF^*R3%DE4aCHZ zqu>xS8LkW+Auv%z-<1Xs92u23R$nk@Pk}MU5!gT|c7vGlEA%G^2th&Q*zfg%-D^=f z&J_}jskj|Q;73NP4<UD^T*M!yxMr=U!@&!rJfydk7CE7PGb<{)^=nM9Le#FQ=GkV~ z)_A$YPAn35??iNa@`g-wBX><4k*Y%pXPU2Thoqr+5uH1yEYM|VtBPW6lXaetokD0u z9qVek6Q&wk)tFbQ8(^HGf3Wp16gKmr>G;#G(HRBx?F`9AIRboK+;OfHaLJ(P>IP0w zyTbTkx_THEOs%Q&aPrxbZrJlio+hCC_HK<4%f3ZoSAyG7Dn`=X=&h@m*|UYO-4Hq0 z-Bq&+Ie!S##4A6OGoC~>ZW`Y5J)*ouaFl_e9GA*VSL!O_@xGiBw!AF}1{tB)z(w%c zS1Hmrb9OC8>0a_$BzeiN?rkPLc9%&;1CZW*4}CDDNr2gcl_3z+WC15&H1Zc2{o~i) z)LLW=WQ{?ricmC`G1GfJ0Yp4Dy~Ba;j6ZV4r{8xRs`13{dD!xXmr^Aga|C=iSmor% z8hi|pTXH)5Yf&v~exp3o+sY4B^^b*eYkkCYl*T{*=-0HniSA_1F53eCb{x~1k3*`W zr~};p1A`k{1DV9=UPnLDgz{aJH=-LQo<5%+Em!DNN252xwIf*wF_zS^!(XSm(9eoj z=*dXG&n0>)_)N5<wxn0{TP0tnD=JAzVUcIUoR85Xt>oc6v!>-bd(2ragD8O=M|wGW z!xJQS<)u70m&6OmrF0WSsr@I%T*c#Qo#Ha4d3COcX+9}hM5!7JIGF>7<~C(Ear^Sn zm^ZFkV6~Ula6+8S?oOROOA6$C&q&dp`>oR-2Ym3(HT@O7Sd5c~+kjrmM)YmgPH*tL zX+znN>`tv;5eOfX?h{AuX^LK~V#gPCu=)Tigtq9&?7Xh$qN|%A$?V*v=&-2F$zTUv z`C#WyIrChS5|Kgm_GeudCFf;)!WH7FI60j^0o#65o6`w*S7R@)88n$1nrgU(oU0M9 zx+EuMkC>(4j1;m6N<sS-ys^qbJhGY7%0ZoC7dK=j7bGdau`J`{>oGqEkpJYJ?vc|B zOlwT3<tNmX!mXZdsEW2s2`|?DC8;N?2tT*Lfq)F*|4vf>t&UgL!pX_P*6g36`ZXQ; z9~Cv}ANFnJGp(;ZhS(@FT;3e)0)Kp;h^x;$*xZn*k0U6-&Fw<BqOnDKEdld8!Qk{Z zjI1+R_ciEqL3CLOv$+J~YVpzIy`S&V{koIi$Lj}ZFEMN=!rL1?_EjSryIV+OBiiJ- zIqT$oSMA>I=uOGaODdrsp-!K$Ac32^c{+FhI-HkYd5v=`PGsg%6I`4d9Jy)uW0y%) zm&j^9WBAp*P8#kGJUhB!L?a%h$hJgQrx!6KCB_TRo%9{t0J7KW8!o1B!NC)VGLM5! zpZy5Jc{`r{1e(jd%jsG7k%I+m#C<kI0i<ajCqQC!(pKlSsMl7M2N^mP%W`BGKb?hm zBK`pddcg5+WhE#$46+K<Z!1CW-hZdo7hAw13ZUVqwW*}&ujL=eh{m~phuOy=JiBMN z7FaCUn6boJ!M=6PtLN6%cveGkd12|1B{)kEYGTx#IiMN&re0`}NP-_{E-#FxOo3*P zkAXSt{et292KfgGN`AR|C`p{MRpxF-I?+`ZY1Vsv>GS*BPA65ZVW~fLYw0dA-H_}O zrkGFL&P1PG9p2(%Qi<evvBkNEkQkM%A>EWm6x;U-U&I#;Em$nx-_I^wtgw3xUPVVu zqSuKnx&dIT-XT+T10p;yjo1Y)z(x1fb8Dzfn8e yu?e%!_ptzGB|8GrCfu%p?(_ zQccdaaVK$5bz;*rnyK{_SQYM>;aES6Qs^lj9lEs6_J+%nIiuQC*fN;z8md>r_~Mfl zU%p5Dt_YT>gQqfr@`cR!$NWr~+`CZb%dn;WtzrAOI>P_JtsB76<bUr7Lsb65vEd}g z5JhMCmn#UeH#6Cew?bxogM)$x5ed{E)%2nWY5rb@Clvh$(JzQ#!CsQ(2I4QnhDDJ^ zYL%2bf8?`y)Ro=x{(dw<4^)(H^z7~3nfYFh-r7yBBb=l3V8dE-Dr&a%qs<OYcajo2 z(4Nw|k5_OQ@6zHmcIK%waj!yoZT(S1YlEFN?8-_lp9nf>PYe*<%H(y>qx-`Kq!X_; z<{RpAqYhE=L1r*M<cT6p|4(5fVa-WIh|@AphR|cJ1`?N>)gNF3B8r(<%8mo*SR2hu zccLRZwGARt)H<F*kMvg%oJV~29ud_q>lo1euqTyM>^!HK*!Q2P;4UYry<i)yWXzKa zM^_qppY~vnIrhL_!;Z9msXMZTTwR{e`yH5t=HdD1Pni7?LqOpLoX}u5n5RfkGBvQ1 z@cdMeR4T6rp^S~>sje@;(<|$&%vQekbn|0Ruu_Io(w4#%p6ld2Yp7tlA`Y$cciThP zKzNGIMPXX%&Ud0uQh!uQZz|FB`4KGD?3!ND?wQt6!n*f4EmCoJUh&b?;B{|lxs#F- z31~HQ`SF4x$&v00@(P+j1pAaj5!s`)b2RDBp*PB=2IB>oBF!*6vwr7Dp%zpAx*dPr zb@Zjq^XjN?O4QcZ*O+8>)|HlrR>oD*?WQl5ri3R#2?*W6iJ>>kH%KnnME&TT<gNU{ zn$Veg044#l=Z-&wsmEZhnw7IwT7Cd}hiZ%ke)-GzAR-Dt6)8Cb6>@Z<Y-SEE^OC5H z=$M0HjdWR5p?n;s9OTXrEa1eGt}G;Eu)ifSop!$z#6V<>zrHS$Q%LC?n|e>V+D+8D zYc4)QddFz7I8#}y#Wj6>4P%34dZH<AWj}HgE@5&D9Ra@o(Km_Gm}5Zb61p%9mDz1% zya$Vd!_U~pDN*Y5%lo}-K~}4&F)rTjJ7uGyV@~kB-XNrIGRiB=UrNxJtX;JHb(EyQ z{!R%v{vC7m|L3bx6lCRb7!mP~Is!r!q&OXpE5nKnH3@l({o}PrL`o>~OUDb?uP%-E zwjXM(?Sg~1!|wI(RVu<h{6ESg9k500(D<HXwz52OGq(JEKS2CJR}8N&E-#%vhhaRN zL#Q6%yUcel+!a#~g&e7w4$3s62d$Dv;SxCxhT}>xbu)-rH+O=igSho_pDCw(c6b=P zKk4ATlB?bj9+HHlh<_!&z0rx13K3ZrAR8W)!@Y}o`?a*JJsD+twZIv`W)@Y?Amu_u zz``@-e2X}27$i(2=9rvIu5uTUOVhzwu%mNazS|lZb&PT;XE2|B&W1>=B58#*!~D&) zfVmJGg8UdP*fx(>Cj^?yS^zH#o-$Q-*$SnK(ZVFkw+er=>N^7!)FtP3y~Xxnu^nzY zikgB>Nj0%;WOltWIob|}%lo?_C7<``a5hEkx&1ku$|)i>Rh6@3h*`slY=9U}(Ql_< zaNG*J8vb&@zpdhAvv`?{=zDedJ23TD&Zg__snRAH4eh~^oawdYi6A3w8<<tS1{)`* zH!u#2_lf&B)x2)tE$?4|aMAYUFZ{|Se7->Ozh@Kw)<E~4fKYaJ{OS+>#bdktM^GVb zrG08?0bG?|NG+w^&JvD*7LAbjED{_Zkc`3H!My>0u5Q}m!+6VokMLXxl`Mkd=g&Xx z-a>m*#G3SLlhbKB!)tnzfWOBV;u;ftU}S!NdD5+YtOjLg?X}dl>7m^gOpihrf1;PY zvll&>dIuUGs{Q<Ww4SS<E23Sm*si$^C!!snD|AFym<+q$`*o0wokE?J{^g?f3>nd- zwIR3oIrct8Va^Tm0t#(bJD7c$Z7DO9*7NnRZorrSm`b`cxz>OI<bVZt$VQ!oMxCu0 zbb7D5OIXV5Ynn@Y6)HLT=1`a=nh7{ee{vr<=$>C;jSE3DO8`hX955ui`s%||YQtt2 z5DNA&pG-V+4oI2s*x^>-$6J?p=I>C|9wZF8z;VjR??Icg?1w2v5Me+FgAeGGa8(3S z4vg*$>zC-WIVZtJ7}o9{D-7d>zCe|z#<9>CFve-OPAYsneTb^JH!Enaza#j}^mXy1 z+ULn^10<XTm*l1Jg2Z;UvGEN!6Wq%I@OP4p{k`RNRKlKFWPt_of11^Gr%_Mg*mVP3 zm?)&3I719~aYcs)TY&q^$zmQ=xoC++VJH@~YG6>+rWLF6j2>Ya@@Kq?26>AqK{A_| zQKb*~F1>sE*=d?A?W7N2j?L09_7n+H<SF8|SM#pTc9|9|rf1w*m4Y0Vdj643qA#D| z!hJzb_-}IrrhkWr{zk_YC%(c-)UJl6Ma!mcbvj&~#yN-UhH?ZQ3TPq4hTVQ$(?eJ6 zNfJ_K+VJDBXN=l!7{2}lq?-$`fq|e&PEONfZDU<_SM+s2_3$vT_yqV<R&KG=K{zS} zKQF$?mYsg%vV|E_E=a*SL!`7*AeN6GMVDXC59yPgi$F2!7&8e}EyHVLwCm{i%<pN! zdc`SbZK}JQj7?6K&|261iHrsnVjdhxu_l_NKs&yy#;#^%8?Jlg`wcTlNZ3urUtEYd zsFE!K0}Eg39)z+J6mLW)#Kn<ok4*6AAE=n*vh*;TpgGnnM|npykFpO|a0`4#SjP^b z2<JG#Qk^#3FeFS`0eooK9|wEmCcvRKI*~6mamFTd^UW9Eg4!J4N9qz*C$3a#F;Sad zi#o9LaqNG5TsiT<`SDtY^`)zkYx$(C5;&K9#(Zj}HolT_st~#C`VS8q%#q1)HN+hT zz9IjVUdZNIp@;b88oR`~DvQL_zmsBy>Gi{VY;MoTGr_)G9)ot$p!-UY5zZ2Xtbm=t z@dpPSGw<TLTZo~Zyx(+AKWvR~{L4S^5I;5+QT9bcQ-4cC{QnLfRBf&Pov~kv@`W6V zA|h{EGx|7msvR1t`a-jF$JZ>gH=QtIcEulQNI>S-#ifbnO5EWkI;$A|pxJd885oM+ zGZ0_0gDvG8q2xebj+fbCHYfAXuZStH2j~|d^sBAzo46(K8n59+T6rzBwK)^rfPT+B zyIFw)9YC-V^rhtK`!3jrhmW-sTmM+tPH+;nwjL#-SjQPUZ53L@A>y*rt(#M(qsiB2 zx6B)dI}6Wlsw%bJ8h|(lhkJVogQZA&n<jl%@&gd%^X|lsDQwDHEiKLCz}r`kC^h0t z(!vYS%C)Ku?w$ti5R##9jSkNC#5)Juc{8XfEhczdGQy8yNrZL6+d0~%V=N|iF{V)E zLT(gH!$j8Mf(1>{?Vgs6gNSXzuZpEyu*xySy8ro07QZ7Vk1!3tJphN_5V7qOiyK8p z#@jcDD8nmtYi1^l8ml;AF<#IPK?!pqf9D4moYk>d99Im}Jtwj6c#+A;f)CQ*f-hZ< z=p_T86jog%!p)D&5g9taSwYi&e<jP@@Q_fbXtVO&n9{e#)jg+D#~q=hoZ<9PIa)>P z#JuEK%+NULWus;0w32-SYFku#i}d~+{Pkho&^{;RxzP&0!RCm3-9K6`>KZpnzS6?L z^H^V*s!8<>x8bomvD%rh>Zp3>Db%kyin;qtl+jAv8Oo~1g~mqGAC&Qi_wy|xEt2iz zWAJEfTV%cl2Cs<1L&DLRVVH05EDq`pH7Oh7sR<WSzBWU(MxAIA&4v~INVdLKA><BK zwCgTxJU0mM{;1UV<^ZRk0SQNNN(;SRZsH7^EDWVUu%^mFfvW{m5jOQuQWSy`f586I zTj}Z4e5WsvkNmBd`TJdfe=^>`NNkL%wi}8n>IXcO40hp+J+sC!W?!krJf!GJNE8uj zg-y~Ns-<~D?yqbzVRB}G>0A^f0!^N7l=$m0OdZuqA<e9rzV|ixGyk9uS=Vov2_ECA z^Sd0M$B)O&tv@%@UmTb%ngcl58ED9TyFp$y4JjFU+g+9EWUl?am<e#4uCGy9Tmt)z z2Y|kWUahugFHsF<J6o!<?X(Ncsy&Wg9<QLPD}g-`PWGHWDY5P6;<Y+5J1vz2Z|PSy zBN?Q^NkxnWq>OQq<EC8_d&#T2smn`YINd-HF@)Op)pBRHnx+Q|Hsv_BpWAPsT1>Lc zX?AEGr1Ht+inZ-Qiwnl@Z0qukd__a!C*CKuGdy5#nD7VUBM^6OCpxCa2A(X;e0&V4 zM&WR8+wErQ7UIc6LY~Q9x%Sn*Tn>>P`^t&idaOEnOd(Ufw#>NoR^1QdhJ8s`h^|R_ zXX`c5*O~Xdvh%q;7L!_!ohf$NfEBmCde|#uVZvEo>OfEq%+Ns7&_f$OR9xsihRpBb z+cjk8LyDm@U{YN>+r46?nn{7Gh(;WhFw6GAxtcKD+YWV?uge>;+q#Xx4!GpRkVZYu zzsF}1)7$?%s9g9CH=Zs+B%M_)+~*j3L0&Q9u7!|+T`^O{xE6qvAP?XWv9_MrZKdo& z%IyU)$Q95AB4!#hT!_dA>4e@zjOBD*Y=XjtMm)V|+IXzjuM;(l+8aA5#Kaz_$rR6! zj>#&^DidYD$nUY(D$mH`9eb|dtV0b{S>H6FBfq>t5`;OxA4Nn{J(+XihF(stSch<f zIn>e7$es&~N$epi&PDM_N`As;*9D^L==2Q7Z2zD+CiU(|+-kL*VG+&9!Yb3LgPy?A zm<g7T4Wx!m(zMlVE_2jX$1$$5DcfL6>7Z&^qRG_JIxK7-FBzZI3Q<;{`DIxtc48k> zc|0dmX;Z=W$+)qE)~`yn6MdoJ4co;%!`ddy+FV538Y)j(vg}5*k(WK)KWZ3WaOG!8 z!syGn=s{H$odtpqFrT#JGM*utN7B((abXnpDM6w56nhw}OY}0TiTG1#f*VFZr+^-g zbP10`$LPq_;PvrA1XXlyx2uM^mrjTzX}w{yuLo-cOClE8MMk47T25G8M!9Z5ypOSV zAJUBGEg5L2fY)ZGJb^E34R2z<C?_X1)4xsl9%Z|w&L9k!F(V>J?}Vf>{~gB!8=5Z) z9y$>5c)=;o0HeHHSuE4U)#vG&KF|I%-cF6f$~pdYJWk_dD}iOA>iA$O$+4%@>JU08 zS`ep)$XLPJ+n0_i@PkF#ri6T8?ZeAot$6JIYHm&P6EB=BiaNY|aA$W0I+nz*zkz_z zkEru!tj!QUffq%)8y0y`T&`fuus-1p>=^hnBiBqD^hXrPs`PY9tU3m0np~rISY09> z`P3s=-kt_cYcxWd{de@}TwSqg<T-v~${38)1dqT{JCO5}Gk$$yZP*X!5)RaGFqqkZ zeHhqUgXb37$91~LS-3Zi29CKKki0sBTh7unqEK$%FG?oo$Sp>*xVhp;E9zCsnXo6z z?f&Sv^U7n4`xr=mXle94HzOdN!2kB~4=%)u&N!+2;z6UYKUDqi-s6AZ!haB;@&B`? z_TRX0%@suz^TRdCb?!vNJYPY8L_}&07uySH9%W^Tc&1pia6y1q#?*Drf}GjGbPjBS zbOPcUY#*$3sL2x4v_i*Y=N7E<UbOmi3K%)5<dOJui+{^+b*shA_w8&X4_Icv*!}kT zW@BG{C%f{(K^kE?tjU`Led*kAj6wB_3f*UyIEV0T9TyMo4`NS;oA7Ec+71eFa;K|G zCyaKKi1bvX9fTLQ+uAgF*@ZR8fB%|JlT8A-jK$7FMyxW>$mR}J%|GUI(>WEr+28+V z%v5{#e!UF*6~G&%;l*q*$V?&r$Pp^sE^i-0$+RH3ERUUdQ0>rAq2(2QAbG}$y{de( z>{qD~GGuO<V3ijl7+~xmS#nUvH{qF0*%7G(r|}BSXsu}HwrFbXWzcYJouIY*34axA z(n@XsPrv%6;|GSbkH9Og>k559Y@%$?N^1ApVL_a704>8OD%8Y%8B;FCt%AoPu8*D1 zLB5X>b}Syz81pn;xnB}%0FnwazlWfUV<Vu@5P52pgIa+J{M)H4nAC<>)Z-~rZg6~b z6!9J$EcE&sEbzcy?CI~=boWA&eeIa%z(7SE^qgVLz??1Vbc1*aRvc%Mri)AJaAG!p z$X!_9Ds;Zz)f+;%s&d<S0a>RcJt2==P{^j3bf0M=nJd&xwUGlUFn?H=2W(*2I2Gdu zv!gYCwM10aeus)`RIZSrCK=&oKaO_Ry~D1B5!y0R=%!i2*KfXGYX&gNv_u+n9wiR5 z*e$Zjju&ODRW3phN925%S(jL+bCHv6rZtc?!*`1<n2%>TyYXT6%Ju=|X;6D@lq$8T zW{Y|e39ioPez(pBH%k)HzFITXHvnD6hw^lIoUMA;qAJ^CU?top1fo@s7xT13Fvn1H z6JWa-6+FJF#x>~+A;D~;VDs2<i>6>^oH0EI`IYT2iagy23?nyJ==i{g4%HrAf1-*v zK1)~@&(KkwR7TL}L(A@C_S0G;-GMDy=MJn2$FP5s<%wC)4jC5PXoxrQBFZ_k0P<n- z??iM<JF!BTjD>{{s@<jPT1+pTPdk3<izB+}jAtjokIz)aPR$L&4%}45Et}?jz0w{( zC4G}+Nu0D*w=ay`v91hMo+V&V8q(a!`~K-2<yR0H)sK+mcY?TAaSS8F<Q+!pSc;`* z*c@5)+ZpT%-!K3O=Z0(hI8LH7KqK>sz+gX`-!=T8rcB(=7vW}^K6oLWMmp(rwDh}b zwaGGd>yEy6fHv%jM$yJXo5oMAQ>c9j`**}F?MCry;T@47@r?&sKHgVe$MCqk#Z_3S z1GZI~nOEN*P~+UaFGnj{{Jo@16`(qVNtbU>O0Hf57-P>x8Jikp=`s8xWs^dAJ9lCQ z)GFm+=OV%AMVqVATtN@|vp61VVAHRn87}%PC^RAzJ%JngmZTasWBAWsoAqBU+8L8u z4A&Pe?fmTm0?mK-BL9t+{y7o(7jm+RpOhL9Kn<D3v{}Wpv2i&ghEZe;t&DmOA_QYc zM+NIUU}=*bkxOJsLKV3e^oGG8rufTpa8R~7Iki1y+fC(UT;;{l19@qfxO@0^!xMA? z#|<YBZ6;vAb>Y#E&qu^}B6=K_dB}*VlSEiC9fn)+V=J;OnN)Ta5v66ic1rG+dGAJ1 z1%Zb_+!$=tQ~lxQrzv3x#CPb?CekEkA}0MYSgx$Jdd}q8+R=ma$|&1a#)TQ=l$1tQ z=tL9&_^vJ)Pk}EDO-va`UCT1m#Uty1{v^A3P~83_#v^ozH}6*9mIjIr;t3Uv%@VeW zGL6(CwCUp)Jq%G0bIG%?{_*Y#5IHf*5M@wPo6A{$Um++Co$wLC=J1aoG93&T7Ho}P z=mGEPP7Gb<mBTnJH7dKM2CB)0*o-AW2E4i5R+rHU%4A2BTVwOqj4zmJqsb|5^*{DT zv^HFARK6@^_1|vU{>voG!uD$k(H3A$Z))+i{Hy?QHdk>3xSBXR0j!11O^mEe9RH<y zF3MI;^J1vHI9U>mw!pvzv?Ua~2_l2Yh~_!s1qS`|0~0)<BWX>YsbHSz8!mG)WiJE| z2<APmuYD%tKwB@0u<C~CKyaC}XX{?mylzkDSuLMkAoj?zp*zFF7q515SrGD~s}ATn z`Ded41yk>f($6TQtt6L_f~ApQYQKSb=`053LgrQq7G@98#igV>y#i==-nEjQ!XNu9 z<h*hnP2Pol+z>~;mE+gtj4IDDNQJ~JVk5Ux6&LCSFL!y=>79kE9=V}J7tD==Ga+IW zX)r7>VZ9dY=V&}DR))xUoV!u(Z|%3ciQi_2jl}3=$Agc<a_3#EUXJj<z2jVv6VHGT zV^v1FiRwA!kPmt}m$qdr&9#-6{QeZqtM3|tRl$sws3Gy`no`Kj@X-)O(^sv>(`RPb z8kEBpvY>1FGQ9W$n>Cq=DIpski};nE)`p3IUw1Oz0|wxll^)4dq3;CCY@RyJgFgc# zKouFh!`?Xuo{IMz^xi-h=StCis_M7y<P{h0$_I#EukRYag9%BMRXh|%Xl7C<>q$u) z?XHvw*HP0VgR+KR6wI)jEMX|ssqYvSf*_3W8zVTQzD?3>H!#>InzpSO)@SC8q*ii- z%%h}_#0{4JG;Jm`4zg};BPTGkYamx$Xo#O~lBirRY)q=5M45n{GCfV<Kqrcu9<z@R zSE>7h9qwyu1NxOMoP4)jjZMxmT|IQQh0U7C$EbnMN<3)Kk?fFHYq$d|ICu>KbY_hO zTZM+uKHe(cIZfEqyzyYSUBZa8;Fcut-GN!HSA9ius`lt<SmSV9vasBl&hE7ciOunD z?%e1Hl-5B3e+<+8CD{j5U*D3h89nV<zn^0g+t=uRKgZiGu)3h;vu#^y`HqWe_=jGm zW2p}*n<!QH%pQ2EV`&z|LD#BOpj0QS9R5#$q}3&-+@GL4F^wO-bcSo|J^I_{LATPF z2$`fUCOO=XxYVD!<7Yz4te$d-_>NebF46ZX_BbZNU}}ZOm{M2&nAN<H$fJIKS=j8q zwXlN!l^_4>L9@0qvih15(|`S~z}m&h!u4x~(%MAO$jHRWNfuxWF#B)E&g3ghSQ9|> z(MFaLQj)NE0lowyjvg8z0#m6FIuKE9lDO~Glg}nSb7`~^&#(Lw{}GVOS>U)m8bF}x zVjbXljBm<v)#bs=9p`s>34Cs-yM6TVusr+3kYFjr28STT3g056y3cH5Tmge~ASxBj z%|yb>$eF;WgrcOZf569sDZOVwoo%8>XO>XQOX1OyN9I-SQgrm;U;+#3OI(zrWyow3 zk==|{<m8xZ#>lt2xrQ%FIXOTejR>;wv(Pb8u8}BUpx?yd(Abh<shPyABw|Ens8m6@ zIg($GO4)<g4x5icbki?U&2%56@tYd`zRs}Nk6R~4!AjVAihB3r8oDhQ8f)v^r}|(y z4B&Q<ARRqYXKQGAeJa_KHe`)04jUO~B=%q#SUlU@pU?apz0v{Al@s`Cvzo)u;2>6? zsoO3VYWkeLnF43&@*#MQ9-i-d0t*xN-UEyNKeyNMHw|A(k(_6QKO=nKMCxD(W(Yop zsRQ)QeL4X3Lxp^L%wzi2-WVSsf61dqliPUM7srDB?Wm6Lzn0&{*}|IsKQW;02(Y&| zaTKv|`U(pSzuvR6Rduu$wzK_W-Y-7>7s?G$)U}&uK;<>vU}^^ns@Z!p+9?St1s)dG zK%y6xkPyyS1$~&6v{kl?Md6gwM|>mt6Upm>oa8RLD^8T{0?HC!Z>;(Bob7el(DV6x zi`I)$&E&ngwFS@bi4^xFLAn`=fzTC;aimE^!cMI2n@Vo%Ae-ne`RF((&5y6xsjjAZ zVguVoQ?Z9uk$2ON;ersE%PU*xGO@T*;j1BO5#TuZKEf(mB7|g7pcEA=nYJ{s3vlbg zd4-DUlD{*6o%Gc^N!Nptgay>j6E5;3psI+C3Q!1ZIbeCubW%w4pq9)MSDyB{HLm|k zxv-{$$A*pS@csolri$Ge<4VZ}e~78JOL-EVyrbxKra^d{?|NnPp86!q>t<&IP07?Z z^>~IK^k#OEKgRH+LjllZXk7iA>2cfH6+(e&9ku5poo~6y{GC5>(bRK7hwjiurqAiZ zg*DmtgY}v83IjE&AbiWgMyFbaRUPZ{lYiz$U^&Zt2YjG<%m((&_JUbZcfJ22(>bi5 z!J?<7AySj0JZ&<-qXX;mcV!f~>G=sB0KnjWca4}vrtunD^1TrpfeS^4dvFr!65knK zZh`d;*VOkPs4*-9kL>$GP0`<?hW@{z#_gXtp%=2VbN+$~z+M($Vf(dl@)t-*82<$( zHi{FrD1wO9L~*Rc0{A2WU%f?ar(T9V1JpQ?M0Q|&{UES|#Z~k2-mj@z)8Rw^(XeYc zomT(B0EF!##4dQq_*NN<%Bo5)&+gCXSGZo`b>(M!j~B;#x?Ba<KDM~HJ!|Zzy=p2e z8;av`GLw{_*RgO(W|UK-<iDeT!t_x1c=M3%wGk|fDk<e0lLe8-5ga6apKYJD`*a3G zBl?Ps)hDb7X`7bW5S=IHr0Mm?fr|$zCf+gmZUrit$5n+)JZG>~&s6CopvO86oM?-? zOw#dIRc;6A<R&%m3DDJhF+|tb*0Yw8mV{a-bf^E~gh66MdsMHkog<r9`fVIVE+h@O zi)iM`rmA-Fs^c=>6T?B`Qp%^<<Dyu<%Kg0H=lq;E!p&UHzSpD1)q%^v)Y8yQkp>U5 z19x(ywSH$_N+Io!6;e?`tWaM$`=D<O;$E>b!gzx|lQ${DG!zb1Zl&|{kX0y6xvO1o z220r<-oaS^^R2pEyY;=Qllqpmue|5yI~D|iI!IGt@iod{Opz@*ml^w2bNs)p`M(Io z|E;;m*Xpjd9l)4G#KaWfV(t8YUn@A;nK^#xgv=LtnArX|vWQVuw3}B${h+frU2>9^ z!l6)!Uo4`5k`<<;E(ido7M6lKTgWezNLq>U*=uz<KVOwgK<qq^3FEy1LAV}ep3|Zt z>&s=cc$1%>VrAeOoUtA|T6gO4>UNqsdK=NF*8|~*sl&wI=x9-EGiq*aqV!(VVXA57 zw9*o6Ir8Lj1npUXvlevtn(_+^X5rzdR>#(}4YcB9O50q97%rW2me5_L=%ffYPUSRc z!vv?Kv>dH994Qi>U(a<0KF6NH5b16enCp+mw^Hb3Xs1^tThFpz!3QuN#}KBbww`(h z7GO)1olDqy6?T$()R7y%NYx*B0k_2IBiZ14&8|JPFxeMF{vSTxF-Vi3+ZOI=Thq2} zyQgjYY1_7^ZQHh{?P))4+qUiQJLi1&{yE>h?~jU%tjdV0h|FENbM3X(KnJdPKc?~k zh=^Ixv*+smUll!DTWH!jrV*wSh*(mx0o6}1@JExzF(#9FXgmTXVoU+>kDe68N)dkQ zH#_98Zv$}lQwjKL@yBd;U(UD0UCl322=pav<=6g>03{O_3oKTq;9bLFX1ia*lw;#K zOiYDcBJf)82->83N_Y(J7Kr_3lE)hAu;)Q(nUVydv+l+nQ$?|%MWTy`t>{hav<vVD zHx;qQ>FSQloHwiIkGK9YZ79^9?AZo0ZyQlVR#}lF%dn5n%xYksXf8gnBm=wO7g_^! zauQ-bH1Dc@3ItZ-9D_*pH}p!IG7j8A_o<ZOCWxl^<k=*NA9oUpW$0D`yCb}VfC~vb z4IkfiRDM@RHlIGG_SRrrd~6$XYP~2Y^<fekveOOZRCv69S{4_se`>94#~>$LR|TFq zZ-b00*nuw|-5C2lJDCw&8p5N~Z1J&TrcyErds&!l3$eSz%`(*izc;-?HAFD9AHb-| z>)id`QCrzRws^9(#&=pIx9OEf2rmlob8sK&xPCWS+nD~qzU|qG6KwA{zbikcfQrdH z<yJStD<g^`?^d44p$8FFXwD2dL810^xg@~^x$C_H#3NSLs8fBVu~K)3BMKCOp^;|& zKPz+s!|fXFr%*`Dg*#A{!QB-jnah3y4$Pe0L2%RM)706&eqyFTNAO2gMd<bcjBp>+ zQg>O<`K4L8rN7`GJB0*3<3`z({lWe#K!4AZLsI{%z#ja^OpfjU{!{)x0ZH~RB0W5X zTwN^w=|nA!4PEU2=LR05x~}|B&ZP?#pNgDMwD*ajI6oJqv!L81gu=KpqH22avXf0w zX3HjbCI!n9>l046)5rr5&v5ja!xkKK42zmqHzPx$9Nn_MZk`gLeSLgC=LFf;H1O#B zn=8|^1iRrujHfbgA+8i<9jaXc;CQBAmQvMGQPhFec2H1knCK2x!T`e6soyrqCamX% zTQ4dX_E*8so)E*TB$*io{$c6X)~{aWfaqdTh=xEeGvOAN9H&-t5tEE-qso<+C!2>+ zskX51H-H}#X{A75wqFe-J{?o8Bx|>fTBtl&tc<VVc3-U5wTq>bdR|<Uon(X?ZiT<< zWC=zLEjacGDZ|?>132Ztqu5X0i-pisB-z8n71%q%>EF}yy5?z=Ve`}hVh{Drv1YWL zW=%ug_&chF11gDv3D6B)Tz5g<uwqk#dj|RK7gNl@*lm*xHRBk*7MnT4(@7VIDfO0u zB?1X+)GR^0j1A{Q#WUmQX%LN=W?aGzO$5=2@yxjXBzxbGO*{DYkV!aJ!$~-FNzvt; z?r)HU;0!4T-%vWzAiHJ?*-ivIq!#dErMvhpJJ^QyZ5n0qmMn+}I>54H0mDHNj<FD1 z&CIP+ZDDy<;b2`JW=0_p9c4p<zwE30JFgdhO2HQiMRBb%Y9ZJ>uKZ+)CKFk4Z|$RD zfRuKLW`1B>B?*RUfVd0+u8h3r-{@fZ{k)c!93t1b0+Q9vOaRnEn1*IL>5Z4E4dZ!7 ztp4GP-^1d>8~LMeb}bW!(aAnB1tM_*la=Xx)q(I0Y@__Zd$!KYb8T2VBRw%e$iSdZ zkwdMwd}eV9q*;YvrBFTv1>1+}{H!JK2M*C|TNe$ZSA>UHKk);wz$(F$rXVc|sI^lD zV^?_J!3cLM;GJuBMbftbaRUs$;F}HDEDtIeHQ)^EJJ1F9FKJTGH<(Jj`phE6OuvE) zqK^K`;3S{Y#1M@8yRQwH`?kHMq4tHX#rJ>5lY3DM#o@or4&^_xtBC(|JpGTfrbGkA z2Tu+AyT^pHannww!4^!$5?@5v`LYy~T`qs7SYt$JgrY(w%C+IWA;ZkwEF)u5sDvOK zGk;G>Mh&elvXDcV69J_h02l&O;!{$({fng9Rlc3ID#tmB^FIG^w{HLUpF+iB`|<Dd z$~}?*yaE3d3m&(}pR(IuL%&h+j{wz$6(l^GO8O{^N!08Gnw7N>NnX)EH+Nua)3Y(c z&{(nX_ht=QbJ%DzAya}!&uNu!4V0xI)QE$SY__m)SAKcN0P(&JcoK*Lxr@P<Bj^D- zi(H(l^zsWRcIm}YCou&G1we!7IMt1dAI3MKk4-3tybIvwniaUWp=||&s9lB&iptb> zY&P=}&B3*UWNlc|&$Oh{BEqwK2+N2U$4WB7Fd|aIal`FGANUa9E-O)!gV`((ZGCc$ zBJA|FFrl<?%m-}hcKbonJcfriSKJrE#oY4SQUGFcnL~;J2>g~9OBp#f7aHodCe{6= zay$6vN~zj1ddMZ9gQ4p32(7wD?(dE>KA2;SOzXRmPBiBc6g`eOsy+pVcHu=;Yd8@{ zSGgXf@%sKKQz~;!J;|2fC@emm#^_rnO0e<D`xKOl)v&1gxhN0@LroTIseY?HHF`U$ zRCxyayrK2fk|YppMxAKP{J=gze_dhnAkmEFp<%l9vvc1zcx#Lz*hP4TNeag4(W!Be zM4c#}`np`hRl02rJ50(%WD@_u_Qk1TUrpL44g>sEn^QxXgJYd`#FPWOUU5b;9eMAF zZhfiZb|gk8aJIw*YLp4!*(=3l8Cp{(%p?ho22*vN9+5NLV0TTazNY$B5L6UKUrd$n zjbX%#m7&F#U?QNOBXkiiWB*_tk+H?N3`vg;1F-I+83{M2!8<^nydGr5XX}tC!10&e z7D36bLaB56WrjL&HiiMVtpff|K%|*{t*ltt^5ood{FOG0<>k&1h95qPio)<rMG98B zE?gDMmn^Zo(`Ek7uvNsnUgUfUfwFF7?z~>2`eL${YAGIx(b4VN*~nKn6E~SIQUuRH zQ+5zP6jfnP$S0iJ<xI2U>@~t!Ai3o`X7biohl<ds?PbGDArmkAV12ldkGzY{P*80E zF=Wk3w#9|J1dAeV)Rlk?%L=ol!+m5%A|(KP`fR=nD^&iHT@Z5DaZ(w0hqfh|V>i;E zT#yXyl{bojG@-TGZzpdVDXhbmF%F9+-^YSIv|<!(knL3!Z+}F~)r$<ET0f@9KVjok zfvU`%FUbk|yAc)S0rB`JBWTLd7hPAAqP2ltlwee5T}#_Gpbl80w-LA;|BD>MT1l3j zrxOFq>gd2%U}?6}8mIj?M<N%?8n+3Rx8(2-`*c@op88}5-iqw*PHkqnj$k8#t^|g> zc077Zc9fq(-)4+gXv?Az26IO6eV`RAJz8e3)SC7~>%rlzDwySVx*q$ygTR5kW2ds- z!HBgcq0KON9*8Ff$X0wOq$`T7ml(@TF)VeoF}x1OttjuVHn3~sHrMB++}f7f9H%@f z=|kP_?#+fve@{0MlbkC9tyvQ_R?lRdRJ@$qcB(8*jyMyeME5ns6ypVI1Xm*Zr{DuS zZ!1)rQfa89c~;l~VkCiH<d?V{)&8(@3=6jm=fW<)H`CSQ9+iNwDH;4S!Xw4H9nux4 zKNscQ&OV9zHF_+cIJ=X)qIF;(!)}sl`hhO)dHz6nA0^W{a9q1^gzxvh-bS1(N273| zq;PSR{n|+%3`+}9Q7}{mC7k)HXlUhkBKH%A@-sEx!4Mlk=^P1dtF=-lC3U?55B}ez z`Fd)kItC)!X+F!>I|PCBd`S*2RLNQM8!g9L6?n`^evQNEwfO@&JJRme+uopQX0%Jo zgd5G&#&{nX{o?TQwQvF1<^Cg3?2co;_06=~Hcb6~4XWpNFL!WU{+CK;>gH%|BLO<b zgJpht0ltX3sE2RJAUcld5MW}&%<sw};dL~bdZ0?zVg~mRcaNBgUZe;8@DKXRQmlOf zAIhHBNh=}LzcTdUnfgd6#GEx350bi`lb)LaBso2CW!*0Xe!UJNwIWeg)QXy=e3bwZ zIJ8=;u}r&BGoF;ftQ-dJ!kBp#;lHIlNwC)v?OHP&#Mh~B%=jdgWQCSqpANGQEkG%n zM?zk5@$%!-gPc55s943P-Mv1>h7@!hsa(>pNDAmpcuVO-?;Bic17R}^|6@8DahH)G z!EmhsfunLL|3b=M0MeK2vqZ|OqUqS8npxwge$w-4pFVXFq$_EKrZY?BuP@Az@(k`L z`<G71X#W|!P3Z{wEvg5Ob7@MbwprRM&*~yi*+R-9I8&p-;yM=Q)z$bTY1}y<i9f;W zGBCz3n1=6)vV6bV+;GN8E|c1rg49&nk_(FLVA<i_4OxA`vE>ViQBSk`y+YwRT;&W| z2e3UfkCo^uTA4}Qmmtqs+nk<f8_TTXgg$0%V(GO^t)<!()wOU}JKa$=7V(Fd-u5kW zfKQU%n`CZ_1jFoAu|=do)|56^VkbaXtt)NlpAubGIJ@ET@k0K*McoNg@OCSSeKJ`( z*rHh**zg=F3rmZ2ux+4MzedRxj4$W0VqcP)lO*|#;Iw4z!Gidd%|ry%SN>#gNr2W4 zTH%hhErhB)pkXR{B!q5P3-OM+M;qu~f>}IjtF%>w{~K-0*jPVLl?Chz&zIdxp}bjx zStp&Iufr58FTQ36AHU)0+CmvaOpKF;W@sMTFpJ`j;3d)J_$tNQI^c<^1o<49Z(~K> z;EZTBaVT%14(bFw2ob@?JLQ2@(1pCdg3S%E4*dJ}dA*v}_a4_P(a`cHnBFJxNobAv zf&Zl-Yt*lhn-wjZsq<9<PjKts@j|?j*H<KG_l+Ikza{2Tyz(8wgaT$KKCTR@fUFh? z9>v-IsXxAxMZ58C@e0!rzhJ+D@9^3~?~yllY^s$?&oNwyH!#~6x4gUrfxplCvK#!f z$viuszW>MFEcFL?>ux*((!L$;R?xc*myjRIjgnQX7<gW>9@UPD$6Dz0jutM@7h_pq z0Zr)#O<^y_K6jfY^X%A-ip>P%3saX{!v;fxT-*0C_j4=UMH+Xth(XVkVGiiKE#f)q z%Jp=JT)uy{&}Iq2E*xr4YsJ5>w^=#-mRZ4vPXpI6q~1aFwi+lQcimO45V-JXP;>(Q zo={U`{=_JF`EQj87Wf}{Qy35s8r1*9Mxg({CvOt}?Vh9d&(}iI-quvs-rm~P;eRA@ zG5?1HO}puruc@S{YNAF3vmUc2B4!k*yi))<5BQmvd3tr}cIs#9)*AX>t`=~{f#Uz0 z0&Nk!7sSZwJe}=)-R^$0{yeS!V`Dh7w{w5rZ9ir!Z7Cd7dwZcK;BT#V0bzTt>;@Cl z#|#A!-IL6CZ@eHH!CG>OO8!%G8&8t4)Ro@}USB*k>oEUo0LsljsJ-%5Mo^MJF2I8- z#v7a5VdJ-Cd%(a+y6QwTmi+?f8Nxtm{g-+WGL>t;s#epv7ug>inqimZCVm!uT5Pf6 ziEgQt7^%xJf#!aPWbuC_3Nxfb&CFbQy!(8ANp<Dkrrv&eXZOx^ui15L`|GC6Zo9J8 zt4l&YYgkq79`qbC=O@Wu>kWLI4oSnH?Q3f?0k1t$3d+lkQs{~(>06l&v|MpcFsyAv zin6N!-;pggosR*vV=DO(#+}4ps|5$`u<dyVk_IJiOQUOA<$>dE%Kdmp?G7B#y%<bi zGVk-OWo?nx8M9(n3)OkC>H`R|i8skKOd9Xzx8xgR$>Zo2R2Ytktq^w#ul4uicxW#{ zFjG_RNlBroV_n;a7U(KIpcp*{M~e~@>Q#Av90Jc5v%0c>egEdY4v3%|K1XvB{O_8G zkTWLC>OZKf;XguMH2-Pw{BKbFzaY;4v2seZV0>^7Q~d4O=AwaPhP3h|!hw5aqOtT@ z!SNz}$of**Bl3TK209@F=T<Nh*u*7J=P_EEnnD=hbiG0v_)iQwN<!vDIogn=iGRs3 zt_h!RUdkzWHMpc*d}k%tjHimct$!p&AH8pRZ+FJo|9w~+h(n#lp$57vBXGLddx*%@ z5%Aj-8?hH;TIkF9$}Pwu0)KjO*p&uKv6>n1+mgZa8yh(Png%Zd6Mt}^NSjy)etQrF zme*llAW=N_8R*O~d2!apJnF%(JcN??=`$qs3Y+~xs>L9x`0^NIn!8mMRFA_tg`etw z3k{9J<p4JZCS-C}49WuHGGruT=x>Ajnl@ygIiJcNHTy02GMAvBVqEss&t2<2mnw!; zU`J)0>lWiqVqo|ex7!+@0i>B~BSU1A_0w#Ee+2pJx0BFiZ7RDHEvE*ptc9md(B{&+ zKE>TM)+Pd>HEmdJao7U@S>nL(qq*A)#eLOuIfA<xx)>S@j`_sK0UEY6OAJJ-kOrHG zjHx`g!9j*_jRcJ%>CE9K2MVf?BUZKFHY?EpV6ai7sET-tqk=nDFh-(65rhjtlKEY% z@G&cQ<5BKatfdA1FKuB=i>CCC5(|9TMW%K~GbA4}80I5%B}(gck#Wlq@$nO3%@QP_ z8nvPkJFa|znk>V92cA!K1rKtr)skHEJD;k8P|R8RkCq1Rh^&}Evwa4BUJz2f!2=MH zo4j8Y$YL2313}H~F7@J7mh>u%556Hw0VUOz-Un@ZASCL)y8}4XXS`t1AC*^>PLwIc zUQok5PFS=*#)Z!3JZN&eZ6ZDP^-c@StY*t20JhCnbMxXf=LK#;`4KHEqMZ-Ly9KsS zI2VUJGY&PmdbM+iT)zek)<hjl_Ql0Z<Zn_qAb)m1SGqs~RuzvnShAB@_vF{e+592q z$DB!xBIZfcH*9&k=wlV*!)l9TjLaF6{FU=1emb_fuvC;885YA6nM5}UqhPTc%&*tY z3h;oOpGO3Hx+t7EjPYfzaZ}+D=ndS&SDnV=GA-}a=$GiNOi~a`1gJao%JzT9!|NX9 z<CC9{n}y#@=&Y6rk@_w$wqbKs!E-bTFZW}3bqJ;f!@40M^ykqGs3;>#Qc#_i4uH43 z@T5SZBrhNCiK~~esjsO9!qBpaWK<`>!-`b71Y5R<QKZFC;tbrvH*7OQFB+SCa^&~y zposW2PUqn>eXQ4AJU~T<enI;Gq30%Z%SsfHco3Z`w^cm#%0^~onRV&P&#QErx)JwE z+PM!k!qYC}ESrBrHoDQz*X1YmFa#(SZW<AV$!J0LWu4IDbZ2bw=%%Iq9Hg*REoc?; z{E60bn(-sNYKAv{(YDGA5Ne~oOSP*!BJYblyeWN+CVy8q4{fMj;2#8%D!ii%2bR=s z%l;FFHzQ~S|A8UKuFT*34q|LzMc~~o#;)Kw9DtS!bp3JQi_@L6HQjXe7-;AjHEUja z>2Njri1CEp5oKw;Lnm)-Y@Z3sEY}X<ceQi^_CPpPY_VEPYF+%Om#`r)SPUG}UXq2Y zpr9=;`h)oB6MR*Xk2Eh4r7Hb|{>IgSy%xo=uek(kAAH5MsV$V3uTUsoTzxp_rF=tx z<QsYQ(;?5S(qGqiH7>V07vlJNKtJhCu`b}*#m&5LV4TAE&%KtHViDAdv#c^x`J7bg z&N;#I2GkF@SIGht6p-V}`!F_~lCXjl1BdTLIjD2hH$J^YFN`7f{Q?OHPFEM$65^!u zNwkelo*5+$ZT|oQ%o%;rBX$+?xhvjb)SHgNHE_yP%wYkkvXHS{Bf$OiKJ5d1gI0j< zF6N}Aq=(WDo(J{e-uOecxPD>XZ@|u-tgTR<972`q8;&ZD!cep^@B5CaqFz|oU!iFj zU0;<Kr(xN%j}{P50=dczD~4jn(p0D1`)Q|ld@m)3cU?5-DDA%Lq4Vd2?$jcNa3@4} zt0;5Pk0HJXk<P(S=!%ZtD121Ne##d}^nRI9>6fQX&~15E53EW&w1s9gQQ~Zk16X%6 zjG`j0yq}4deX2?Tr(03kg>C(!7a|b9qFI?jcE^Y>-VhudI@&LI6Qa}WQ>4H_!UVyF z((cm&!3gmq@;BD#5P~0;_2qg<pD9=9nXg$TuH}wQh9<MTT}D~YJ$+K3jbd)SV}wix zf+zmLDPNc@nH3C;GngJH(K9z-$bm-ym&hXvg&{t=h}^v&Zpkgh>ZhtJS|>WdtjY=q zLnHH~Fm!cxw|Z?Vw8*~?I$g#9j&uvgm7vPr#&iZgPP~v~BI4jOv;*OQ?jYJtzO<^y z7-#C={r7CO810!^s(MT!@@Vz_SVU)7VBi(e1%1rvS!?PTa}Uv`J!EP3s6Y!xUgM^8 z4f!fq<3Wer_#;u!5ECZ|^c1{|q_lh3m^9|nsMR1#Qm|?4Yp5~|e<cTgyd3~1T9l&* zeQ01<P2U~{V&q4>r2?W^7~cl;_r4WSme_o68J9p03~Hc%X#VcX!xAu%1`R!dfGJCp zV*&m47>s^%Ib0~-2f$6oSgn3jg8m%UA;ArcdcRyM5;}|r;)?a^D*lel5C`V5G=c~k zy*w_&BfySOxE!(~PI$*dwG><<WF75p<o9EVVze~dTW<Z_^0lybcm7u?o5{_6x)ND; zb8GQ#!>+-%KT5p?whOUMA*k<9*gi#T{h3DAxzAPxN&Xws8o9Cp*`PA5>d9*Z-ynV# z9yY*1WR^D8|C%I@vo+d8r^pjJ$>eo|j>XiLWvTWLl(^;JHCsoPgem6PvegHb-OTf| zvTgsHSa;BkbG=(NgPO|CZu9gUCGr$8*EoH2_Z#^BnxF0yM~t`|9ws_xZ8X8iZYqh! zAh;HXJ)3P&)Q0(&F>!LN0g#bdbis-cQxyGn9Qgh`q+~49Fqd2epikEUw9ca<Icy-f zOt40c5j7j)$)tP9?uvS*(MhNoK9DyuR}iw#hq(_Yg;FQNx_fxU*Eu(iTCigNUM7t< z>M%V6WgP)532RMRW}8gNS%V%Hx7apSz}tn@bQy!<=lbhmAH=FsMD?leawbnP5BWM0 z5{)@EEIYMu5;u)!+HQ<i|FmCtfdneL-c-Zq4Plvb%6L#`yCeba4_fn4B8J3*R<jzl zfvYN4K`&;0Sxn>WhQ;D3_Cm_NADNeb-f56}<{41aYq8p4=93d=-=q0Yx#knGYfXVt z+kMxlus}t2T5FEyCN~!}90<Qw*O-2+V!RyNwDJ!D4}()%&9a2ilTUH&u5D!U%eI_q zx}xGi`t`GnBsEW*ontVcR-ikx88LbjAhe<X@Zi_w7Y34lxFFrZ2Q&%wKjDtka2LVK zHc8~1#H%sr<^E7ZD2HEuJ^9vl!WfP^A{M0b1kd0=9ymV8H)Sd)K8ApeV;=DNu1w7T zq3y-B$08B=*qJh`RBSq*hM$V1Wi(wSS$C7SwYBw1{q+D%@|+@4!e&J2mmVQuQ$1nJ zGVp>O_X@@PQpuy;kuGz@bWft%diBTx?d)_xWd_-(!LmVrh**oKg!1CNF&LX4{*j|) zIvjCR0I2UUuuEXh<9}oT_zT#jOrJAHNLFT~Ilh9hGJPI1<5`C-WA{tUYlyMeoy!+U zhA#=p!u1R7DNg9u4|QfED-2TuKI}>p#2P9--z;Bbf4Op*;Q9LCbO&aL2i<0O$ByoI z!9;Ght733FC>Pz>$_mw(F`zU?`m@>gE`9_p*=7o=7av`-&ifU(^)UU`Kg3Kw`h9-1 z6`e6+im=|m2v`pN(2dE%%n8YyQz;#3Q-|x`91z?gj68cMrHl}C25|6(_dIGk*8cA3 zRHB|Nwv{@sP4W+Y<?>ZM)VKI>R<dU=sQkg7!lDS83Q3{+&sk$J+O!cATJ_o5Pb&W_ z)bdtK2>lB`n=Oj~Rzx~M+Khz$N$45rLn6k1nvvD^&HtsMA4`s=MmuOJID@$s8Ph4E zAmSV^+s-z8cfv~Yd(40Sh4JG#F~aB>WFoX7ykaOr3JaJ&Lb49=B8Vk-SQT9%7TYhv z?-Pprt{|=Y5ZQ1?od|A<_IJU93|l4oAfBm?3-wk{O<8ea+`}u%(kub(LFo2zFtd?4 zwpN|2mBNywv+d^y_8#<$r>*5+$wRTCygFLcrwT(qc^n&@9r+}Kd_u@Ithz(6Qb4}A zWo_HdBj#V$VE#l6pD0a=NfB0l^6W^g`vm^sta>Tly?$E&{F?TTX~DsKF~poFfmN%2 z4x`Dc{u{Lkqz&y!33;X}weD}&;7p>xiI&ZUb1H9iD25a(gI|`|;G^NwJPv=1S5e)j z;U;`?n}j<Q^Xq~o28<9wN;wOTm1lpjZMh*aUX(~T_Y3#ZnG~Ye&HG?FC8<&_!tool z+@`jls~3x-4`e?M70izyrpLQDV~@R;Ddqa8ubupC&5hxJ!0Qn2&@6(rv>nY6rA{V^ zxTd{bK)Gi^odL3l989DQlN+Zs39Xe&otGeY(b5>rlIqfc7Ap4}EC?j<{M=hlH{1+d zw|c}}yx88_xQr`{98Z!d^FNH77=u(p-L{W6RvIn40f-BldeF-YD>p6#)(Qzf)lfZj z?3wAMtPPp>vMehkT`3gToPd%|D8~4`5WK{`#+}{L{jR<c)T{dJNa_2~nx}yzR>UMt zrFz+O$C7y8$M&E4@+p+o<?<4i!4ikchlAhrd(TAazwXC#eTotZ4)SbD2SX9vq+(V^ zQt>V5c%uYzbqd2Y%SSgYy#xh4G3hQv>V*BnuKQhBa#=o<cI|?w3{ulWOpdl|%RYTA zSx@6KnTs$R(CM2sHs-QJn!^oj_3M4<ToCw0Dysc#3eTjWBJ-T+adb-$?`_4mF<8?g zSKY1V7KhH!;LK22fSg)B*<uJ7m~6W3CUps0^d9*o2V_Gub>ZB~w{azUB+q%bRe_R^ z>fHBilnRTUfaJ201czL8^~Ix#+qOHSO)A|xWLqOxB$dT2W~)e-r9;bm=;p;RjYahB z*1hegN(VKK+ztr~h1}YP@6cfj{e#|sS`;3tJhIJK=tVJ-*h-5y9n*&cYCSdg#EHE# zSIx=r#qOaLJoVVf6v;(okg6?*L_55atl^W(gm^yjR?$GplNP>BZsBYEf_>wM0Lc;T zhf&gpzOWNxS>m+mN92N0{;4uw`P+9^*|-1~$<g_U{SU`H<rGXK<wL9(P>uXpggj4- z^SFc4`uzj2OwdEVT@}Q`(^EcQ_5(ZtXTql*yGzdS&vrS_w<Vq*ng}zPHZxXbJ~5By z5q!Q1MEDSMNOWX9zY-~b`9@lU+AIe>>~~ra|Nb5abwf}Y!uq6R5f&6g2ge~2p(%c< z@O)cz%%rr4*cRJ5f`n@lvHNk@lE1a*96Kw6lJ~B-XfJW%?&-y?;E&?1AacU@`N`!O z6}V>8^%RZ7SQnZ-<!aS@7Sy5FdEA^NVBSolPfAv!POl_VDW*<OY|VOa1x+Nt4h}kC zF5f5bMcr5zsZz*#rv_qyg5_y;>z$(jsX`amu*5Fj8g!3RTRwK^`2_QH<oOlcTv0T* zq^FmDESBJUwy8>e;_2y_n|6gSaGyPmI#kA0sYV<_qOZc#-2BO%hX)f$s-Z3xlI!ub z^;3ru11DA`4heAu%}HIXo&ctujzE2!6DIGE{?Zs>2}J+p&C$rc7gJC<HidCCr+8PF zWiTVZ>35gxhflorvsb%sGOxpuWhF)dL_&7&Z99=5M0b~Qa;Mo!j&Ti_kXW!86N%n= zSC@6Lw>UQ__F&+&Rzv?gscwAz8IP!n63>SP)^62(HK98nGjLY2*e^OwOq`3O|C92? z;TVhZ2SK%9AGW4ZavTB9?)mUbOoF`V7S=XM;#3EUpR+^oHtdV!GK^nXzCu>tpR|89 zdD{fnvCaN^^LL%amZ^}-E+214g&^56rpdc@yv0b<3<Gcz@z*K79?oK~*UzGlKFJXT z{XOryj|k?!nDS(G1LtLxYD^Cq?c?_!zYn!x^#tLjQ6=Wb!)yrQsQW$6U<7{9%v7a- zv*ocK5QN4V3`xVyd7lYi<tse4LzLtbxdam8l#%xfBL@jXus_3m`H&T(SG4<1{Xtfu zMb*~2c3zevaj8sJ+%2=tK7#q$!xF@Xc_%7Ws0|ayo4RjQhmCcKBx<ij=1uikr$^Pt z9|pP=(@t-<MX5uDFk4~}Y&YCR_($i(L2tZ?=zYb8^M2`}T)&sKMTvyh6Hf2vk#&E} zXFWd3BT@?-Qm?6K=3M(cZ#LOR`xDd$o~J$T>}Ys?)f|fXN4oHf$six)-@<;W&&_kj z-B}M5U*1sb4)77aR=@%I?|Wkn-QJVuA96an25;~!gq(g1@O-5VGo7y&E_srxL6ZfS z*R%$gR}dyONgju*D&?geiSj7SZ@ftyA|<I`YtD1a%3oCr%5@GGkBtN{5mnwPyOw=G z)5mh1d5f2bd0O6v9}uRb?jQWt0Hmbh{Lw~%;q96e<JYrfUt;Ww3`|kuk8YLozMnJA zL-%S-b>}(*Y4KbvU!YLsi1EDQQCnb+-cM=K1io78o!v<D2B&P2)99nqSy|&vmf_z? z=eWr~Nb^z}4FA|*1-U>*);o<<Bb~caN#d%78rHzz&LtUD8*+uiPJdUJ<!gd#RBLsK z$C!13l?*$0KTH~HOk{`~({IY19$^eGtD0+`Ng;Krabee-ZmxY?a!#sR^lIs7X@lqE z)iFHx46*Kc<U3%gK1Qg`N*=%M8g<Qr@DDqezg1<>XwjaQH%)uIP&Zm?)Nfbfn;jIr z)d#!$gOe3QHp}2NBak@yYv3m(CPKkwI|{;d=gi552u?xj9ObCU^DJFQp4t4e1tPzM zvsRIGZ6VF+{6PvqsplMZWhz10YwS={?`~O0Ec$`-!klNUYtzWA^f9m7tkEzCy<_nS z=&<(awFeZvt51>@o_~>PLs05CY)$;}Oo$VDO)?l-{CS1Co=nxjqben*O1BR>#9`0^ zkwk^k-wcLCLGh|XLjdWv0_Hg54B&OzCE^3NCP}~OajK-LuRW53CkV~Su0U>zN%yQP zH8UH#W5P3-!ToO-2k&)}nFe`t+mdqCxxAHgcifup^gKpMObbox9LFK;LP3}0dP-UW z?Zo*^nrQ6*$FtZ(>kLCc2LY*|{!dUn$^RW~m9leoF|@Jy|M5p-G~j%+P0_#orRKf8 zvuu5<*XO!B?1E}-*SY~MOa$6c%2cM+xa8}_8x*aVn~57v&W(0mqN1W`5a7*VN{SUH zXz98DDyCnX2EPl-`Lesf`=AQT%YSDb`$%;(jUT<emmKF_zfZmU9B12q_dyZ<_@h~k zvEq1`Vx6X|zFHC1f>rNen$NPJrlpPDP}prI>Ml!r6bCT;mjsg<oj3+@ct5lWE*J;5 z4E~(;FwK{V8;n^S+p_aly?)G^7&y`S%eK)TJhe8?@}L_b8H};V-{Fr!7~z`5Jn&~y zle5N-{eo+>@X^#&<}CGf0Jt<ps|x+2W>R{Ecwd&)2zuhr#nqdgHj+g2n}GK9CHuwO zk><uMX@X}I+5rrj?NaO6BMSeLuD{-~8R-Gl2xdC9#?M&n3M8$1#r~F<bd_yU6EE{Y z#eCFVb$%8`qmYLY$VN_bTcap4)*3IM0tVFqt0C)EHHU4$9K2ap4$RYn7cYx68f*63 zqjgq9d3s#J0z)IOp-dbsoyDl3q&F;wDIxirPuXzvw6-Mhm_%B8`dB@kd7fLXw-%?$ zoq?`st6r0!H5QKHrVxu9;wFCr4k6@&eG$(7Z2Wi#T=t;uR8LkI#eWjbL4#SB+RR!} zkvLwWmhxM!7BIsi5NeXcxeg6+4^H8NJB5=2mJzA06v|{=fl0X|ig2$)&h*GM&JpHp zr`8`GjG!&l9EyWchuo>oZxy{v<eHuSsx&-tHadS1q^a4f?|RTjYB^sRK14!iW+^lB z!ebp33Hf8OUb(D`D*|G{AftC98wHP4tb?H!)=@9haZJ)F+0;HQc5`Qlnk&U!fz)-9 z%lX#G)XFlYmyE^D)O;h749_^`>cOL)$8-}L^iV<p27<5%t|ClWJe$Rd_|U|Ck(u@6 zTgwrC&(m^cFeKDxIl7TOJH#1Wo==_x;yAITBFJ1z$*I>fJHAGfwN$prHjY<ZwGVKY zZ8+b}fUD+>V0ju}8%jWquw>}_W6j~m<}Jf!G?~r5&Rx)!9JNX!ts#SGe2HzobV5); zpj@&`cNcO&q+%*<%D<T}5E&SDWDa4Lg;*h`<xw$&SGrTg$|CXl_i7+njSd+)yvyz7 z+0<o|PMTJL)R>7za|?m5qlmFK$=MJ_iv{aRs+BGVrs)98BlN^nMr{V_fcl_;<BiuS ztTFCwthZrVHPPZYBIYp#EouQ9MTH{-OaLh9+PRHAG3=cqP}nnZd8AjsX8sR)@*@Na z!0>jkzRju+c-y?gqBC_@J0dFLq-D9@VN&-`R9U;nv$Hg?>$oe4N&Ht$V_(JR3TG^! zzJsbQb<dCovVFFYER#ii{pf+`)Dd4mJA8V_i{)g*7b35$IR9(S%Er0t1yr7X5aERc zeK=jG4aV7X*X+)C@a&31a^^wDy<E&Lu}Ry(`Um&dxXGiHJfU<|q(iByYWWLIS^^>i zFE6-{#9{G{+Z}ww!ycl*7rRdmU#_&|DqPfX3CR1I{Kk;bHwF6jh0opI`UV2W{*|nn zf_Y@%wW6APb&9Rr<YY$Si*BvV^N#m{QYOko?PXQXU(La}0lCv3qWQ$bi`=<yuf89@ zA3M_;xKTP6E^K#?{F`hD*rTDZhZ!h73@a^*&yKH>bEN=PQRBEpM(N1w`81s=(xQj6 z-eO0k9=Al|>Ej|Mw&G`%q8e$2xVz1v4DXAi8G};R$y)ww638Y=9y$ZYFDM$}vzusg zUf+~BPX>(SjA|tgaFZr_e0{)+z9i6G#lgt=F_n$d=beAt0Sa0a7>z-?vcjl3e+W}+ z1&9=|vC=$co}-Zh*%3588G?v&U7%N1<wSL*V~9}~r(eJ^+Xr3`-m(Sj@@;y|({lFw zG+a0jI%A@viPJ_TgyiV93C-_fon>Qf-wNWJ)(v`iO5KHSkC5&g7CrKu8V}uQGcfcz zmBz#Lbqwqy#Z~UzHgOQ;Q-rPxrRNvl(&u6ts4~0=KkeS;zqU<rCYLCOgtuj&A3yvF z)|<)nA^eF$@T!K+ig@JbUkyVVJP%Y)>Rz%!-ERppmd%0v>iRlEf+H$yl{_8TMJzo0 z>n)`On|7=WQdsqhXI?#V{>+~}qt-cQbokEbgwV3QvSP7&hK4R{Z{aGHVS3;+h{|Hz z6$Js}_AJr383c_+6sNR|$qu6dqHXQTc6?(XWPCVZv=)D#6_;D_8P-=zOGEN5&?~8S zl5jQ?NL$c%O)*bOohdNwGIKM#jSAC?BVY={@A#c9GmX0=T(0G}xs`-%f3r=m6-cpK z!%waekyAvm9C3%>sixdZj+I(wQlbB4wv9xKI*T13DYG^T%}zZYJ|0$Oj^YtY+d$V$ zAVudSc-)FMl|54n=N{BnZTM|!>=bhaja?o7s+v1*U$!v!qQ%`T-6fBvmdPbVmro&d zk07TOp*KuxRUSTLRrBj{mjsnF8`d}rMViY8j`jo~Hp$fkv9F_g(jUo#Arp;Xw0M$~ zRIN!B22~$kx;QYmOkos@%|5k)!QypDMVe}1M9tZfkpXKGOxvKXB!=lo`p?|R1l=tA zp(1}c6T3Fwj_CPJwVsYtgeRKg?9?}%oRq0F+r+kdB=bFUdVDRPa;<s*Z4&z%Yqy%U zOeHw$WK*_?C+%QKv}yj&a(!5Ni>E~~>2$w}>O>v=?|e>#(-Lyx?nbg=ckJ#5U6;RT zNvHhXk$<cTrzyFrc-kzJ80|Sr7cPKJYnxQh*Fg9@b51h^!>P}m9wSvFyU3}=7!y?Y z=fg$PbV8d7g25&-jOcs{%}wTDKm>!Vk);&rr;O1nvO0VrU&Q?TtYVU=ir`te8SLlS zKSNmV=+vF|ATGg`4$N1uS|n??f}C_4Sz!f|4Ly8#yTW-FBfvS48Tef|-46C(wE<BN zM?~(EkSJJWr_!W7-HptZRmK`p&C>O_%pPhUC5$-~Y?!0vFZ^Gu`x=m7X99_?C-`|h zfmMM&Y@zdfitA@KPw4Mc(YHcY1)3*1xv<iSQWzdA1>W9V-r4n-9ZuBpFcf{yz+SR{ zo$ZSU_|fgwF~aakGr(9Be`~A|3)B=9`$M-TWKipq-NqRDRQc}ABo*s_5kV%doIX<z zw8f$0lCeVGD0^!OedVm2t32)213YQ46v=o)@UsVzy`KZ%hr__m!jsQbd@}{{Vg1hz z`m2-BpqxgapTIephm4Cik^T6BeWfmt%BA@BRlvqT0ILcR0(vVdxD!}~F3BI!@Yuk* zM2~`l5+!SvcPoj}AC@Q9McO3!2ke!m5VcW3F%a(IA*N@sL73(w3O(3~t5el4Dq{JU z21IfDfV)n^u4cGvvfJlGe~Q~Yzeudy#8j^ja>7LRLRau_gd@Rd_aLFXGSU+U?uAqh z8qusWW<lz^u{++i(BMS0kYpMurHwdx8=v!VDug!+!?SoQ%5#Z9_%%XQ)=}5@(OGY$ z!*NFRMlh?b0mZ-o&{hRY(q#;?AsyI_fTbU3vvt{86Gd^<UxrFKXriAuhLyoz-Rb+| z<1fH@C7QEgQz2VdIb}M#v@~+roe%YIUs5B>cvgQ&wu{|sRXmv?sl=xc<$6AR$+cl& zFNh5q1~kffG{3lDUdvEZu5c(aAG~+64FxdlfwY^*;JSS|m~CJusvi-!$XR`6@XtY2 znDHSz7}_Bx7zGq-^5{stTRy|I@N=>*y$zz>m^}^{d&~h;0kYiq8<^W<E|75Z!A4X; zB0ckyjy2crb1=uu;OnTA+AN(`$!y~N){ZywsrcJ<-RJ-6@#;QH|7$vRI{)h?@p2NX z`N+$B?J?QE9;Pm%%)e)K9b55SBEW5@Zc4|{XhN6&8tG6ODyNFgS%k;enJu!|jBjTn zO3=N;{~$Us+^lM79~#+NVdMuMV*xv4<srsN5l%(Xfx|TFiWsSLu6VKb8+BQX%9T6) zLIA<^s*!o98&YNSoO#lh*yl=4IaXWU@%j6|nHVJL2?PUhARrz8&IkW*Q<47%jpzTI z4gPog-xBcuLB=pm_-|9W&~MFVz_3-f?M6(XIxnIg#$zC^5E`10kVD2)wtP_r+-MVn zDB)nM192c6VQ(1fw5pgW;z9QPF|WVy-Pi3Kqyd;SXdDvK@g#36c@VC&u=_B=n%w}x z9G42<h(@l93n9W)B(s=&>q7Dz0w31ShO^~LUfW6rfitR0(=3;Uue`Y%y@ex#eKPOW zO~V?)M#AeHB2kovn1v=n^D?2{2jhIQd9t|_Q+c|ZFaWt+r&#yrOu-!4pXAJuxM+Cx z*H&>eZ0v8Y`t}8{TV6smOj=__gFC=eah)mZt9gwz>>W$!>b3O;Rm^Ig*POZP8Rl0f zT~o=Nu1J|lO>}xX&#P<uNYpwDdsi81$~7Dv-8cIS(lR52^!TF;6k;WMGV`thcu^6S z@T3rgu^2l&lSgk|u&dqJ2P;_lKd-gsz+E~nyy$zL@l8HyyxzgF#YH#@jXdT>58%Yl z83`HRs5#32Qm9mdCrMlV<JBDhyZ+y^N%S92djDerOElqpRE}K*p`=oMP>|NKNC+Z~ z9OB8xk5HJ>gBLi+m@(pvpw)<om*<*&g*ukIpJ5#uX6#7U*X+*MN|7vZ8*HK)=`Y9r z)#d;zRimk{mmRK`xtmKSn@imtSD%un-#&@aHsi(XFSqmU+t2^tlw;mwe}X*y&#AIH zlv#=?W?e4tr=1o`K<LAS)WBGaORGt!_L??}o8QF5X|ARAXjcw9(=`^ih&uvZ?3o=4 ztCfj-M@ZND9Dnt(PEoh14OzzWaAN5QQ)tU}4*nXvp1HQ^w*zt7KrnA5B`0hYyAdFC zH+>1(OaVJKs*$Ou#@Knd#bk+V@y;YXT?)4eP9E5{J%KGtYinNYJUH9PU3A}66c>Xn zZ{Bn0<;8$WCOAL$^NqTjwM?5d=RHgw3!72WRo0c;+houoUA@HWLZM;^U$&sycWrFd zE7ekt9;kb0`lps{>R(}YnXlyGY}5pPd9zBpgXeJTY_jwaJGSJQC#-KJqmh-;ad&F- z-Y)E>!&`Rz!HtC<wKL>z>%yO<y&s#nmyWumg2@9<En(?C^(|rjP3fstXvL7F_}@s~ zK?}vRELPAe=@^SDzf;4gMIY~6wbR)ERQj~L^17FRR>J|v(u7P*I$jqEY3}(Z-orn4 zlI?CYKNl`6I){#2P1h)y(6?i;^z`N3bxTV%wNvQW+eu|x=kbj~s8rhCR*0H=iGkSj zk2<D*!UmdR0qg)7cV>3lr9kr|p7#qKL=UjgO`@UnvzU)`&fI>1Qs7ubq{@+lK{hH* zvl6eSb9%yngRn^T<;jG1SVa)eA>T^XX=yUS@NCKpk?ovCW1D@!=@kn;l_BrG;hOTC z6K&H{<8K#dI(A+zw-MWxS+~{g$tI7|SfP$EYKxA}LlVO^sT#Oby^grkdZ^^lA}uEF zBSj$weBJG{+Bh@Yffzsw=HyChS(dtLE3i*}Zj@~!_T-Ay7z=B)+*~3|?w`Zd)Co2t zC&4DyB<B`NVJ>!o&YgSw+fJn6`sn$e)29`kUwAc+1MND7YjV%lO;H2}fNy>hD#=gT ze+-aFNpyKIoXY~Vq-}OWPBe?Rfu^{ps8>Xy%42r@RV#*QV~P83jdlFNgkPN=T|Kt7 zV*M`Rh*30&AWlb$;ae130e@}Tqi3zx2^JQHpM>j$6x`#{mu%tZlwx9Gj@Hc92IuY* zarmT|*d0E~vt6<+r?W^UW0&#U&)8B6+1+;k^2|FWBRP9?C4Rk)HAh&=AS8FS|NQaZ z2j!iZ)nbEyg4ZTp-zHwVlfLC~tXIrv(xrP8PAtR{*c;T24ycA-;auWsya-!kF~CWZ zw_uZ|%urXgUbc@x=L=_g@QJ@m#5beS@6W195Hn7>_}z@Xt{DIEA`A&V82bc^#!q8$ zFh?z_Vn|ozJ;NPd^5uu(9tspo8t%&-U9Ckay-s@DnM*R5rtu|4)~e)`z0P-sy?)kc zs_k&J@0&0!q4~%cKL)2l;N*T&0;mqX5T{Qy60%JtKTQZ-xb%KOcgqwJmb%MOOKk7N zgq})R_6**{8A|6H?fO+2`#QU)p$Ei2&nbj6TpLSIT^D$|`TcSeh+)}VMb}LmvZ{O| ze*1IdCt3+yhdYVxcM)Q_V0bIXLgr6~%JS<<&dxIgfL=Vnx4YHuU@I34JXA|+$_S3~ zy~X#gO_X!cSs^XM{yzDGNM>?v(+sF#<0;AH^YrE8smx<36bUsH<L8f?5hvib^(w-z zQO~nQ$dVU0i#a3ki#~Zfn+z)A0X6&+uTO~YY-95PED8rYa#tnOB_5j0D(OiyL`p9s zv+IJ_k!HYz5YcKEc7QF88Nvot?2oM%4aDY1Bzw#ErO+K${;d;Xz}Qst%^Hxe<y|{# z0i<}um0l#qNYBrEHp~^dRc(MW&*nx$<xOZo&ngs@b)HTJL5#EBLw4XB%N{_Unwz1| zV8i$e7agBMpxq^UD+OBzpAA4~Wm`dImRWzuo^(m(ArJer$O=jb))nZ!p#}ai;I|`b zxh~i8wmS;I?uK@A5wM9(c}p9|(M`BOW}{O$gH|yS=WST0IY5xeK;n^|OTOu06VXGL ziLV81^Z>bN#y57K8WEu(`qHvQ6cAZPo=J5C(lSmUCZ57Rj6cx!e^rfaI5%w}unz}4 zoX=nt)FVNV%QDJH`o!u9olLD4O5fl)xp+#RloZlaA92o3x4->?rB4`gS$;<QP`qnB zxyR|2?xCkFimDvX6HOV?^)Ex~)EDlr;3{Zk;-f=p?%7c@-P$(ps9BR^)$rFZsteaA z;pEqzR194rw0JOm6L~PJ9F(nNaRn+j%W1SvOz`}E|6u-%XnRuFO#whbo=$_b&QmEc zz35A#zc{~jeDG0s#(%Oyh`}`Lr28fKNg=;!oXo#n2s2b!wHSqmp4gLtkq~?+{}p*~ zmyPE6L~1+ln$95dm03gaCX?Mx^?0LvGdEce@^Fw=4Li}NJ(PPrnJG8UTM7f;`bHcw z$Z`@wnD>WO{R;Z3>cG3IgFX2EA?PK^M}@%1%A;?f6}s&CV$cIyEr#q5;yHdNZ9h{| z-=dX+a5elJoDo?Eq&Og!nN6A)5yYpnGEp}?=!C-V)(*~z-+<AB{~}$sb=b_3)fww3 z1aC=mU#wAjt*hH!O=_Rq0hO_a&wY#~Xao9@|NW*<bx}+viW;viI*Z+I?~t{%B+v(! zDDr@@d60%bC|=S0vZozViq<m)h@uyR_WM|>?kY1Q7qs#Rsy%hu_60rdbB+QQNr?S1 z?;xtjUv|*E3}HmuNyB9aFL5H~3Ho0UsmuMZELp1a#CA1g`P{-mT?B<X1H9ohvAM^; z+8=gDne1h_tC$>chuLEtK}!QZ=3AWakRu~?f9V~3F;TV`5%9Pcs_$gq&CcU}r8gOO zC2&SWPsSG{&o-LIGTBqp6SLQZPvYKp$$7L4WRRZ0BR$Kf0I0SCFkqveCp@f)o8W)! z$%7D1R`&j7W9Q9CGus_)b%+B#J2G;l*FLz#s$hw{BHS~WNLODV#(!u_2Pe&tMsq={ zdm7>_WecWF#D=?eMjLj=-_z`aHMZ=3_-&E8;ibPmM}61i6J3i<Ry9$0oO(dC+M{8z zs~&fm$9WhF63%!K_Mm6jbUbs_bSm8+)$j`QmCxcnfVz-~LWI0Pvt$(Iiice=m6f#A znKpqTEVc`=3la-JE~IF8T$O7$xw2vGNtATg%;ITCJQ$<SdLX>s*=dKf%HC>=xbj4$ zS|Q-hWQ8T5mWde6h@;mS+?k=89?1FU<%qH9B(l&O>k|u_aD|DY*@~(`_pb|B#rJ&g zR0(~(6<MTX1VH`>8fpUPz6TdS@4JT5MOPrqDh5_H(eX1$P2SQrkvN8sTxwV>l0)Qq z0pzTuvtEAKRDkKGhhv^jk%|HQ1DdF%5oKq5BS>szk-CIke{%js?~%@$uaN3^Uz6Wf z_iyx{bZ(;9y4X&>LPV=L=d+A}7I4GkK0c1Xts{rrW1Q7apHf-))`BgC^0^F(>At1* za@e7{lq%yAkn*NH8Q1{@{lKhRg*^TfGvv!Sn*ed*x@6>M%aaqySxR|oNadYt1mpUZ z6H(<Ni{=BqKRj2FW+}Co`K?u{@WLS%pQm3TU}Q0c616}yg+(R+@sl}k&>rupHYf&Z z29$5g#|0MX#aR6TZ$@eGxxABRKakDYtD%5BmKp;HbG_ZbT+=81E&=XRk6m_3t9PvD zr5Cqy(v?gHcYvYvXkNH@S#Po~q(_7MOuCAB8G$a9BC##gw^5mW16cML=T=ERL7wsk zzNEayTG?mtB=x*wc@ifBCJ|irFVMOvH)AFRW8WE~U()QT=HBCe@s$dA9O!@`zAAT) zaOZ7l6vyR+Nk_OOF!ZlZmjoImKh)dxFbbR~z(cM<ohJsx2;$$S(LMO!JiV@-OGlmm z`NdjOOy9O@m26&M`?ASmTQ{@=-K%#U)U7w<-rclq>hfeX1l7S_`;h|v3gI}<v)x_w zvu)Dq)`qX%>n9$sSQ>+3@AF<e#LTCwgPu=4ybha;DXu-e#IUo*sWeYFrWHoigJs{Q zYu_ff&j$_|OP<X2&rv4d2FV^~F@43}*F8@FN!r^c>Ay9=B_y$)q;Wdl|C-X|VV3w8 z2S#>|5dGA8^9%Bu&fhmVRrTX>Z7{~3V&0UpJNEl0=N32euvDGCJ>#6dUSi&PxFW*s zS`}TB>?}H(T2lxBJ!V#2taV;q%zd6fOr=SGHpoSG*4PDaiG0pdb5`jelVipkEk%FV zThLc@Hc_AL1#D&T4D=w@UezYNJ%0=f3iVRuVL5H?eeZM}4W*bomebEU@e2d`M<~uW zf#Bugwf`VezG|^Qbt6R_=U0}|=k;mIIakz99*>FrsQR{0aQRP6ko?5<7bkDN8evZ& zB@_KqQG?ErKL=1*ZM9_5?Pq%lcS4uLSzN(Mr5=t6xHLS~Ym`UgM@D&VNu8e?_=<G2 z$Y^_uSNUz|Ag`4k$;;4dC>nSFtF$u@hpPSmI4Vo_t&v?>$~K4y(O~Rb*(MFy_igM7 z*~yYUyR6yQgzWnWMUgDov!!g=lInM+=lOmOk4L`O?{i&qxy&D*_qorRbDwj6?)!ef z#JLd7F6Z2I$S0iYI={rZNk*<{HtIl^mx=h>Cim*04K4+Z4IJtd*-)%6XV2(M<qEcY zKpTExU9W`Sp|>CscPiw_a+y*?BKbTS@BZ3AUao^%Zi#PhoY9Vib4N>SE%4>=Jco0v zH_Miey{E;FkdlZSq)e<{`+S3W=*ttvD#hB8w=|2aV*D=yOV}<n%QCtpFj!1iP3=++ zF%bul8RQG~xNUT@7_D%fDp&f9U3+!yV(BF^EJ6M?ggfgy%D_aSJLQh<Q8L9^3Z4lP zSliD?8{L~ZN{}ULe$or4iOcd9fCXx)uXD>(&p%0LbEWH$&@$X3x~CiF-?ejQ*N+-M zc8zT@3iwkdRT2t(XS`d7`tJQAjRmKAhiw{WOqpuvFp`i@Q@!KMhwKgs<K(HF*wpN5 zv(vj1XA8yT@r9sbul0J^6}T8DTrg3?UvaTK(_8@BG(vOS@R#A};jf~t=|7FM{G%;V z$moCx(glgj5-;%1QM|u%2d3FX97|2!-{zNf(~wZQL8&V6ON(xoE>A}%@sw8Xo5Y=F zhRJZg)O4uqNWj?V&&vth*H#je6T}}p_<>!Dr#89q@uSjWv~JuW(>FqoJ5^ho0%K?E z9?x_Q;kmcsQ@5=}z@tdljMSt9-Z3xn$k)kEjK|qXS>EfuDmu(Z8|(W?g<kN}okBu| z`906+8rq=5w?nFA6VC1#eQVZ_=+&soKuCq9J4-B?5ajOsO<ZqBE?J2XT_J8fPV98+ zk#wtSBTro80%$s5KaeCr*oviwvkprv-mw0v@x!YSCMmDCbzwIduaRkq+nkD$>Y6-l z@R_#M8=vxKMAoi&PwnaIYw2COJM@atcgfr=zK1bvjW?9B`-+Voe$Q+H$j!1$Tjn+* z&LY<%)L@;zhnJlB^Og6I<R<r5yYZK!bg%i+z^Gb9&z&*Z#pVBay5jNKYESI$cqK!; zs%j&*N?LE3ILkbKV_0UUpL<A`zeQtv+?k$&h|~*OX&e)^SV^abQ&PMGXtX3fI2kT= z2Y%RbH`bf;|K;F8Mxo)Ov25Y*lHOz#D>&BOR-m?{IW;tyYC%FZ!&Z>kGjHJ6cqM-F z&19n+e1=9AH1VrVeHrIzqlC`w9=*zfmrerF?JMzO&|Mmv;!4DKc(sp+jy^Dx?(8>1 zH&yS_4yL7m&GWX~mdfgH*AB4<e8V;o9`b8>{CKo;+egw=PrvkTaoBU+P-4u?E|&!c z)DKc;>$$B6u*Zr1SjUh<mc1^2+c=@@6(J4|#?}T_|M2b62=4`4F-ba1m43BpL!aCj zR^w2TEDEd$X7pi$++6T@mH_M(zN#-+gi}U5eaDqd^tUG_>2)FeuWLWHl5TH(UHWkf zLs>7px!c5n;rbe^lO@ql<wf#W%s8knI~Th~JR_Kl+2&@Zoorl!op+Ba_ZYj2yD(^E z$}7%1B7{$MlPHueM^5x<Vc5^Pd5$8yYQ@u;!UngDNs9O`zY)-uu_X-;n9-+TuAb`^ z<H1e|G%#k-<p?8qbT%m<kMd#1>YLzlDVp(z?6r<WUtyWnlD^G9B?_Ur{&KCOuHNMq zk|B^K_<0Q-9-+@;d#BY&2k-R$to<44{eG#pW>PZel=YB)Uv&n!2{+Mb$-vQl=xKw( zve&>xYx+jW_NJh!FV||r?;hdP<!CWxpcsZKiv4>*jOXYcLCp>DOtJ?2S^)DkM{{Eb zS$!L$e_o0(^}n3tA1R3-$SNvgBq;DOEo}fNc|tB%%#g4RA3{|euq)p+xd3I8^4E&m zFrD%}nvG^HUAIKe9_{tXB;tl|G<%>yk6R;8L2)KUJw4yHJXUO<O#J#etA!EQr#Ixj zZuFu$GT+Wpqx#)|V^@Cm`sHrRN~=Je%6V#~5_a6U7SazOW-GgiQtB4%%~2(B0iBsg z;PpJsF|+l@`Wy@y_OtfS`JgrB)rNO1MTjsxeQ7|k!FQ^3n6kbM;^~mT&4KxW*m77y zq%{h&JwttX7mQ1|xDfr$rzHoYHzjn|^DmxVimK9<IM)^a;|9O2LO78(*WR_|D40bM z4}thc%eqOsDqUE<D1~O4evp0zw~wzT!F>PM>(-+jxq4R;z8H#>rnJy*)8N+$wA$^F z<U&lTYAkA<S9x1+2s?lu2|Zd2nj#EvZB!v_&9eAD+8*)ghmbT+{)~_^Px6pMeOz2X zv~Wjk&YGtROVvA~E^msuyea-{C!TM*WVVa4lhy%2Gi&UvdDpYWzNapW2o<z2pU37x zeudIr){wxOzdWU}R?Ue;nbpX4`c>N+H*3t)eFEgxLw+Nw3};4WV$qj&_D`%ADV2%r zJCPCo%{=z7;`F98(us5JnT(G@sKTZ^;2FVitXyLe-S5(hV&Ium+1pIUB(CZ#h|g)u zSLJJ<@HgrDiA-}V_6B^x1>c9B6%~847JkQ!^KLZ2skm;q*edo;UA)~?SghG8;QbHh z_6M;ouo_1rq9=x$<`Y@EA{C%6-pEV}B(1#sDoe_e1s3^Y>n#1Sw;N|}8D|s|VPd+g z-_$QhCz`vLxxrVMx3ape1xu3*wjx=yKSlM~nFgkNWb4?DDr*!?U)L_VeffF<+!j|b zZ$Wn2$TDv3C3V@BHpSgv3JUif8%hk%OsGZ=OxH@8&4`bbf$`aAMchl^qN>Eyu3JH} z9-S!x8-s4fE=lad%Pkp8hAs~u?|uRnL48O|;<hL9ZDZTaoVqCgAV4_fXA_B>*DEU! zuS0{cpk%1E0nc__2%;apFsTm0bKtd&A0~S3Cj^?72-*Owk3V!ZG*PswDfS~}2<8le z5+W^`Y(&R)yVF*tU_s!XMcJS`;<i5$MCe|U*GT!0%*LADX`D^%6_<=D#Ru0`TRN8+ zm@tIK)49`32a<@shitOU#x<QU%nW!IzfjK>(Tr`J0%>p=Z&InR%D3@KEzzI+-2)HK zuoNZ&o=wUC&+*?ofPb0a(E6(<2Amd6%uSu_^-<1?hsxs~0K5^f(L<W1_uUGAdyXWF z-9E^}>sGqgEF^+0_H=uNk9S0bb!|O8d?m5gQjUKevPaO+*VfSn^2892K~%crWM8+6 z25@V?Y@J<9w%@NXh-2!}SK_(X)O4AM1-WTg>sj1{lj5@=q&dxE^9xng1_z9w9DK>| z6Iybcd0<ba%T-PM@iR4f+hWNy2(Dh#%r^4ZjOOcYUhl?lcc*@SuVYF<0NRX~sTl15 z&yX+gisvpMdp($7GpQ}~BtfayBnqkt65sVAS)H#))Ya=X_9qRpsELVk)K-Umx|Q>e zy<csGv$iOY<#zt!tLyihB^h0nm-w?)HRS0&_TFyZkN{(*U!r-+J#Pt@VJw|c&+Ad7 zGuhURv<S1E^2YPq{$<>i;Ew!KBRIfGPGytQ6}z}MeXCfLY0?9%RiyagSp_D1?N&c{ zyo>VbJ4Gy`@Fv+5cKgUgs~na$>BV{*em7PU3%lloy_aEovR+J7TfQKh8BJXyL6<F; zULuFu;b(C;CC(l^>|P8un-Jnq(ghd!_HEOh$zlv2$~y3krgeH;9zC}V3<xe_B^^Vb z>f`uDtW(%mT#944DQa~^8ZI+zAUu4U(j0YcDfKR$bK#gvn_{JZ<YX};laf~yTsdEA zA~Ra?VD!R`MyGN9;7}SV*B=q$h>>|gZ5+)u?T$w<UlM8Es^_5l0fa>7Q%F^;!Wk?G z(le7r!ufT*cxS}PR6hIVtXa)i`d$-_1KkyBU>qmgz-=T};uxx&sKgv48akIWQ89F{ z0<y9Cbjk%^#=J+qPnsNw%*mP1XLirQj9jh94t22gxgVWwR*I>XiY?WM^~;|T8zBOr zs#zuOONzH?svv*jokd5SK8wG>+yMC)LYL|vLqm^PMHcT=`}V$=nIRHe2?h)8WQa6O zPAU}d`1y(>kZiP~Gr=mtJLMu`i<2CspL|q2DqAgAD^7*$xzM`PU4^ga`ilE134XBQ z99P(LhHU@7qvl9Yzg$M`+dlS=x^(m-_3t|h>S}E0bcFMn=C|KamQ)=w2^e)35p`zY zRV8X?d;s^>Cof2SPR&nP3E+-LCkS0J$H!eh8~k0qo$}00b=7!H_I2O+Ro@3O$nPdm ztmbOO^B+IHzQ5w>@@@J4cKw5&^_w6s!s=H%&byAbUtczPQ7}wfTqxxtQNfn*u73Qw zGuWsrky_ajPx-5`R<)6xHf>C(oqGf_Fw|-U*GfS?xLML$kv;h_pZ@Kk$y0X(S+K80 z6^|z)*`5VUkawg}=z`S;VhZhxyDfrE0$<offD>(PMurAxl~<>lfZa>JZ288ULK7D` zl9|#L^JL}Y$j*j`0-K6kH#?bRmg#5L3iB4Z)%iF@SqT+Lp|{i`m%R-|ZE94Np7Pa5 zCqC^V3}B(FR340pmF*qaa}M}+h6}mqE~7Sh!9bDv9YRT|>vBNAqv09zXHMlcuhKD| zcjjA(b*XCIwJ33?CB!+;{)vX@9xns_b-VO{i0y?}{!sdXj1GM8+$#v>W7nw;+O_9B z_{4L;C6ol?(?W0<6taGEn1^uG=?Q3i29sE`RfYCaV$3DKc_;?HsL?D_fSYg}SuO5U zOB_f4^vZ_x%o`5|C@9C5+o=mFy@au{s)sKw!UgC&L35aH(sgDxRE2De%(%OT=VUdN ziVLEmdOvJ&5*tCMKRyXctCwQu_RH%;m<lO9)YlolKp~SHA~$RD@rJEPJ4LfFabjtz zzIU?%C*Qz8oJB~DbsOtV|5q`38L}^8Uq{e{^Ki<?YLnvYT2b=9GoWdOL!w)E5Yy?N zCPB}zb-LW~opI;Pm$>*$YK&m;jtbdH#Ak~13T1^f89tn`A%QEHWs~jnY~E}p_Z$XC z=?YXLCkzVSK+Id`xZYTegb@W8_baLt-Fq`Tv|=)JPbFsKRm)4UW;yT+J`<<s6L^~# zDKX^stn#n?Mc#=>)%#ue9DPOkje)YF2fsCilK9MIIK>p*`fkoD5nGfmLwt)!KOT+> zOFq*VZktDDyM3P5UOg`~XL#cbzC}eL%qMB=Q5$d89MKuN<r)TznqqP**!jJ?cnTT2 zaaf?rvaC;><?H&|zm@ni*?D9zRWNdd5|h7<r<^y7j=M<<S|!iYxdgG*6u6u?mWfD3 zB)<Dfkbae`fO#+9WEYybHeZv}*cbdmPDkPU(jb+Sl1(!A;;QmZ9oNWRty}&5QMWy9 zX_w<YIby`Y;2BC{-IfA^=3f)~-*KF*rKr=krZyJeUl;NhG@Ajb2fr2VF0H7ZuP8_; zl#_lD<2+R)LHx3c896sfpWG@kpwT@>#$6|4gx_Jt0Gfn8w&q}%lq4QU%6#jT*MRT% zrLz~C8FYKHawn-EQWN1B75O&quS+Z81(zN)G>~vN8VwC+e+y(`>HcxC{MrJ;H1Z4k zZWuv$w_F0-Ub%MVcpIc){4PGL^I7M{>;hS?;eH!;<Yf7EM>gmcOE66z3;Z1Phqo(t zVP(Hg6q#0gIKgsg7L7WE!{Y#1nI(45tx2{$34dDd#!Z0NIyrm)HOn5W#7;f4pQci# zDW!FI(g4e668kI9{2+mLwB+=#9bfqgX%!B34V-$wwSN(_cm*^{y0jQtv*4}eO^sOV z*9xoNvX)c9isB}Tgx&ZRjp3kwhTVK?r9;n<haxnrRq){mtk9A+#MWR@iL>!x>^XYT z@Q^7zp{rkIs{2mUSE^2!Gf6$6;j~&4=-0cSJJDizZp6LTe8b45;{AKM%v99}{{FfC zz709%u0mC=1KXTo(=TqmZQ;c?$M3z(!xah>aywrj40sc2y3rKFw4jCq+Y+u=CH@_V zxz|qeTwa>+<|H%8Dz5u>ZI5MmjTFwXS-Fv!TDd*`>3{krWoNVx$<133`(ftS?ZPyY z&4@ah^3^i`vL$BZa>O|Nt?ucewzsF)0zX3qmM^|waXr=T0pfIb0*$AwU=?Ipl|1Y; z*Pk6{C-p4MY;j@IJ|DW<V4g+WfmkDAI{!240rBm;^p*C?EK5<-i6<dFN`<4WIVA6x zQ_A}VBKmDESd)f<tKV+_7{`O-ZQ=Kw_N>>QHZQJcp;Z~?8(Q+Kk3^0qJ}SCk^*n4W zu9ZFwLHUx-$6xvaQ)SUQcYd6fF8&x)V`1bIuX@>{mE$b|Yd(qomn3;bPwnDUc0F=; zh*6_((%bqAYQWQ~odER?h>1mkL4kpb3s7`0m@rDKGU*oyF)$j~Ffd4fXV$?`f~rHf z<dmhsigJ=rWi_aV`WXyhB>B%Y)@5SXZvfwm10RY5X?TEo)PK_`L6qgBp=#>fO49$D zDq8Ozj0q6213tV5Qq=;fZ0$|KroY{Dz=l@lU^J)?Ko@ti20TRplXzphBi>XGx4bou zEWrkNjz0t5j!_ke{g5I#PUlEU$Km8g8TE|XK=MkU@PT4T><2OVamoK;wJ}3X0L$vX zgd7gNa359*nc)R-0!`2X@FOTB`+oETOPc=ubp5R)VQgY+5BTZZJ2<L28T@@Z{~(FZ zheu(w_rw1D2_zLx!dpDtOmwLC!DhBIo<Q>?9QwnO=<wr%&Gfr?0?EHFALMv;_+d?S zzAg%@ydS-+C)WJy(gMckj>dnulIUF3gFn;BODC2)65)HeVd%t86sL7Rv^Y+nbn+&l z6BAJY(ETvwI)Ts$aiE8rht4KD*qNyE{8{x6R|%akbTBzw;2+6<pQ&SDXNQj*or8md z6z#{?Yky9DqRtSV0CMnGmM?NZ;=ja)lj3y_HwGOxfijBU4|3qigw`1zRQjL!B8PR+ zaRn%p#eR@M4(R@Wz!rx^(f#sKB!vBtl{_H&pMv^{xCn<;&`rM&o>Echkt+W+`u^XX z_z&x%n<Jwv#rI=O_ITYt8jK&7Lbvimxh?Mpm*TNff4FbaUEWX?w*B~|ab(^T*a99t zcJ#fCD8IP<V1pf_@pm2K2=}<d0_Y2*QClSUBi8yzf&VOuJ`CJAoEUwr?!mKD=5}o2 zV^&)q)<B;SMXmbXj|caU)A+-MMW5C}&8F^$XYi3}kDOaQe6Z+qH3z$S;;<vL9ydXD zI5~P97&YCq9}$m^On$P-pTjcf#j%4IH8Sc*nG=+l4{M+gXHaFf{g{b8PUBySZmJ4r UfUyy3EX0IC28@JalTrWuAK7&_a{vGU literal 0 HcmV?d00001 diff --git a/server/gradle/wrapper/gradle-wrapper.properties b/server/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..a4413138c --- /dev/null +++ b/server/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/server/gradlew b/server/gradlew new file mode 100644 index 000000000..b740cf133 --- /dev/null +++ b/server/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/server/gradlew.bat b/server/gradlew.bat new file mode 100644 index 000000000..25da30dbd --- /dev/null +++ b/server/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/server/settings.gradle b/server/settings.gradle new file mode 100644 index 000000000..dbbee46fb --- /dev/null +++ b/server/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'haengdong' diff --git a/server/src/docs/asciidoc/billAction.adoc b/server/src/docs/asciidoc/billAction.adoc new file mode 100644 index 000000000..dfd7e26db --- /dev/null +++ b/server/src/docs/asciidoc/billAction.adoc @@ -0,0 +1,121 @@ +== 지출 액션 + +=== 지출 액션 생성 + +operation::createBillActions[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"REQUEST_EMPTY", + "message":"지출 금액은 비어 있으면 안됩니다." + }, + { + "code":"REQUEST_EMPTY", + "message":"지출 내역은 비어 있으면 안됩니다." + }, + { + "code":"BILL_ACTION_TITLE_INVALID", + "message":"앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다." + }, + { + "code":"BILL_ACTION_PRICE_INVALID", + "message":"지출 금액은 10,000,000 이하의 자연수여야 합니다." + }, + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + } +] +---- + +=== 지출 액션 수정 + +operation::updateBillAction[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"REQUEST_EMPTY", + "message":"지출 내역 제목은 공백일 수 없습니다." + }, + { + "code":"REQUEST_EMPTY", + "message":"지출 금액은 공백일 수 없습니다." + }, + { + "code":"BILL_ACTION_TITLE_INVALID", + "message":"앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다." + }, + { + "code":"BILL_ACTION_PRICE_INVALID", + "message":"지출 금액은 %,d 이하의 자연수여야 합니다." + }, + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"BILL_ACTION_NOT_FOUND", + "message":"존재하지 않는 지출 액션입니다." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + } +] +---- + +=== 지출 액션 삭제 + +operation::deleteBillAction[snippets="path-parameters,http-request,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + } +] +---- diff --git a/server/src/docs/asciidoc/billActionDetail.adoc b/server/src/docs/asciidoc/billActionDetail.adoc new file mode 100644 index 000000000..a8f19f21b --- /dev/null +++ b/server/src/docs/asciidoc/billActionDetail.adoc @@ -0,0 +1,93 @@ +== 지출 상세 + +=== 지출 상세 조회 + +operation::findBillActionDetailsTest[snippets="path-parameters,http-request,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code": "EVENT_NOT_FOUND", + "message": "존재하지 않는 행사입니다." + }, + { + "code": "BILL_ACTION_NOT_FOUND", + "message": "존재하지 않는 지출 액션입니다." + }, + { + "code": "BILL_ACTION_DETAIL_NOT_FOUND", + "message": "존재하지 않는 참여자 지출입니다." + }, + { + "code": "TOKEN_NOT_FOUND", + "message": "토큰이 존재하지 않습니다." + }, + { + "code": "TOKEN_EXPIRED", + "message": "만료된 토큰입니다." + }, + { + "code": "TOKEN_INVALID", + "message": "유효하지 않은 토큰입니다." + }, + { + "code": "FORBIDDEN", + "message": "접근할 수 없는 행사입니다." + } +] +---- + +=== 지출 상세 수정 + +operation::updateBillActionDetailsTest[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code": "REQUEST_EMPTY", + "message": "멤버 이름은 공백일 수 없습니다." + }, + { + "code": "REQUEST_EMPTY", + "message": "지출 금액은 공백일 수 없습니다." + }, + { + "code": "EVENT_NOT_FOUND", + "message": "존재하지 않는 행사입니다." + }, + { + "code": "BILL_ACTION_NOT_FOUND", + "message": "존재하지 않는 지출 액션입니다." + }, + { + "code": "BILL_ACTION_DETAIL_NOT_FOUND", + "message": "존재하지 않는 참여자 지출입니다." + }, + { + "code": "BILL_ACTION_PRICE_NOT_MATCHED", + "message": "지출 총액이 일치하지 않습니다." + }, + { + "code": "TOKEN_NOT_FOUND", + "message": "토큰이 존재하지 않습니다." + }, + { + "code": "TOKEN_EXPIRED", + "message": "만료된 토큰입니다." + }, + { + "code": "TOKEN_INVALID", + "message": "유효하지 않은 토큰입니다." + }, + { + "code": "FORBIDDEN", + "message": "접근할 수 없는 행사입니다." + } +] +---- diff --git a/server/src/docs/asciidoc/event.adoc b/server/src/docs/asciidoc/event.adoc new file mode 100644 index 000000000..72511b91b --- /dev/null +++ b/server/src/docs/asciidoc/event.adoc @@ -0,0 +1,205 @@ +== 행사 + +=== 행사 생성 + +operation::createEvent[snippets="http-request,request-body,request-fields,response-body,response-fields,http-response,response-cookies"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"REQUEST_EMPTY", + "message":"행사 이름은 공백일 수 없습니다." + }, + { + "code":"EVENT_NAME_LENGTH_INVALID", + "message":"행사 이름은 2자 이상 30자 이하만 입력 가능합니다. 입력한 이름 길이 : 21" + }, + { + "code":"EVENT_NAME_MULTIPLE_BLANK", + "message":"행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : 공백 문자" + }, + { + "code":"EVENT_PASSWORD_INVALID", + "message":"비밀번호는 4자리 숫자만 가능합니다." + } +] +---- + +=== 행사 관리자 로그인 + +operation::eventLogin[snippets="path-parameters,http-request,request-body,request-fields,http-response,response-cookies"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"REQUEST_EMPTY", + "message":"비밀번호는 공백일 수 없습니다." + }, + { + "code":"PASSWORD_INVALID", + "message":"비밀번호가 일치하지 않습니다." + } +] +---- + +=== 행사 정보 조회 + +operation::getEvent[snippets="path-parameters,http-request,response-body,response-fields,http-response"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + } +] +---- + +=== 행사 전체 참여자 목록 조회 + +operation::findAllEventMember[snippets="path-parameters,http-request,response-body,response-fields,http-response,response-fields"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + } +] +---- + +=== 행사 전체 액션 이력 조회 + +operation::findActions[snippets="path-parameters,http-request,http-response,response-fields"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + } +] +---- + +=== 행사 참여자 이름 변경 + +operation::updateEventMemberName[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + + { + "code":"MEMBER_NAME_CHANGE_DUPLICATE", + "message":"중복된 참여 인원 이름 변경 요청이 존재합니다." + }, + { + "code":"MEMBER_NOT_EXIST", + "message":"현재 참여하고 있지 않는 인원이 존재합니다." + }, + { + "code":"REQUEST_EMPTY", + "message":"멤버 이름은 공백일 수 없습니다." + }, + { + "code":"MEMBER_NAME_LENGTH_INVALID", + "message":"멤버 이름은 1자 이상 4자 이하만 입력 가능합니다." + }, + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"MEMBER_NAME_DUPLICATE", + "message":"중복된 행사 참여 인원 이름이 존재합니다." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"만료된 토큰입니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + } +] +---- + +=== 행사 참여자 삭제 (특정 참여자의 모든 참여자 액션 삭제) + +operation::deleteAllMemberActionByName[snippets="path-parameters,http-request,http-response,request-cookies"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + } +] +---- + +=== 행사 어드민 권한 확인 + +operation::authenticateEvent[snippets="http-request,http-response,request-cookies"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code": "EVENT_NOT_FOUND", + "message": "존재하지 않는 행사입니다." + }, + { + "code": "TOKEN_NOT_FOUND", + "message": "토큰이 존재하지 않습니다." + }, + { + "code": "TOKEN_EXPIRED", + "message": "만료된 토큰입니다." + }, + { + "code": "TOKEN_INVALID", + "message": "유효하지 않은 토큰입니다." + }, + { + "code": "FORBIDDEN", + "message": "접근할 수 없는 행사입니다." + } +] +---- diff --git a/server/src/docs/asciidoc/index.adoc b/server/src/docs/asciidoc/index.adoc new file mode 100644 index 000000000..8e1bcd2d0 --- /dev/null +++ b/server/src/docs/asciidoc/index.adoc @@ -0,0 +1,15 @@ +ifndef::snippets[] +:snippets: ../../build/generated-snippets +endif::[] += 행동대장 +:source-highlighter: highlightjs :hardbreaks: +:toc: left :doctype: book :icons: font :toc-title: 전체 API 목록 :toclevels: 2 :sectlinks: +:sectnums: +:sectnumlevels: 2 + + +include::{docdir}/event.adoc[] +include::{docdir}/memberBillReport.adoc[] +include::{docdir}/memberAction.adoc[] +include::{docdir}/billAction.adoc[] +include::{docdir}/billActionDetail.adoc[] diff --git a/server/src/docs/asciidoc/memberAction.adoc b/server/src/docs/asciidoc/memberAction.adoc new file mode 100644 index 000000000..897102c8d --- /dev/null +++ b/server/src/docs/asciidoc/memberAction.adoc @@ -0,0 +1,100 @@ +== 참여자 액션 + +=== 참여자 액션 생성 + +operation::createMemberAction[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"REQUEST_EMPTY", + "message":"멤버 액션은 공백일 수 없습니다." + }, + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"MEMBER_ACTION_STATUS_INVALID", + "message":"멤버 액션은 IN, OUT만 가능합니다. 입력한 멤버 액션: I_N" + }, + { + "code":"MEMBER_ALREADY_EXIST", + "message":"현재 참여하고 있는 인원이 존재합니다." + }, + { + "code":"MEMBER_NOT_EXIST", + "message":"현재 참여하고 있지 않는 인원이 존재합니다." + }, + { + "code":"MEMBER_NAME_DUPLICATE", + "message":"중복된 이름이 존재합니다. 입력된 이름: 이상, 이상, 감자, 백호" + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + } +] +---- + +=== 현재 행사에 참여 중인 (탈주 가능한) 참여자 목록 조회 + +operation::getCurrentMembers[snippets="path-parameters,http-request,http-response,response-fields"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + } +] +---- + +=== 참여자 액션 삭제 + +operation::deleteMemberAction[snippets="path-parameters,http-request,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"ACTION_NOT_FOUND", + "message":"존재하지 않는 액션입니다." + }, + { + "code":"MEMBER_ACTION_NOT_FOUND", + "message":"존재하지 않는 멤버 액션입니다." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + } +] +---- diff --git a/server/src/docs/asciidoc/memberBillReport.adoc b/server/src/docs/asciidoc/memberBillReport.adoc new file mode 100644 index 000000000..18bd7d3ef --- /dev/null +++ b/server/src/docs/asciidoc/memberBillReport.adoc @@ -0,0 +1,17 @@ +== 정산 + +=== 참여자별 정산 결과 조회 + +operation::getMemberBillReports[snippets="path-parameters,http-request,response-body,response-fields,http-response,http-request"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + } +] +---- diff --git a/server/src/main/java/server/haengdong/HaengdongApplication.java b/server/src/main/java/server/haengdong/HaengdongApplication.java new file mode 100644 index 000000000..4a84c6120 --- /dev/null +++ b/server/src/main/java/server/haengdong/HaengdongApplication.java @@ -0,0 +1,15 @@ +package server.haengdong; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@Slf4j +@SpringBootApplication +public class HaengdongApplication { + + public static void main(String[] args) { + SpringApplication.run(HaengdongApplication.class, args); + } + +} diff --git a/server/src/main/java/server/haengdong/application/ActionService.java b/server/src/main/java/server/haengdong/application/ActionService.java new file mode 100644 index 000000000..bcf5e8b55 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/ActionService.java @@ -0,0 +1,39 @@ +package server.haengdong.application; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.response.MemberBillReportAppResponse; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.action.MemberBillReport; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class ActionService { + + private final BillActionRepository billActionRepository; + private final MemberActionRepository memberActionRepository; + private final EventRepository eventRepository; + + public List<MemberBillReportAppResponse> getMemberBillReports(String token) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + List<BillAction> billActions = billActionRepository.findByAction_Event(event); + List<MemberAction> memberActions = memberActionRepository.findAllByEvent(event); + + MemberBillReport memberBillReport = MemberBillReport.createByActions(billActions, memberActions); + + return memberBillReport.getReports().entrySet().stream() + .map(entry -> new MemberBillReportAppResponse(entry.getKey(), entry.getValue())) + .toList(); + } +} diff --git a/server/src/main/java/server/haengdong/application/AuthService.java b/server/src/main/java/server/haengdong/application/AuthService.java new file mode 100644 index 000000000..d9352ad53 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/AuthService.java @@ -0,0 +1,41 @@ +package server.haengdong.application; + + +import java.util.Map; +import server.haengdong.domain.TokenProvider; +import server.haengdong.exception.AuthenticationException; +import server.haengdong.exception.HaengdongErrorCode; + +public class AuthService { + + private static final String TOKEN_NAME = "eventToken"; + private static final String CLAIM_SUB = "sub"; + + private final TokenProvider tokenProvider; + + public AuthService(TokenProvider tokenProvider) { + this.tokenProvider = tokenProvider; + } + + public String createToken(String eventId) { + Map<String, Object> payload = Map.of(CLAIM_SUB, eventId); + + return tokenProvider.createToken(payload); + } + + public String findEventIdByToken(String token) { + validateToken(token); + Map<String, Object> payload = tokenProvider.getPayload(token); + return (String) payload.get(CLAIM_SUB); + } + + private void validateToken(String token) { + if (!tokenProvider.validateToken(token)) { + throw new AuthenticationException(HaengdongErrorCode.TOKEN_INVALID); + } + } + + public String getTokenName() { + return TOKEN_NAME; + } +} diff --git a/server/src/main/java/server/haengdong/application/BillActionDetailService.java b/server/src/main/java/server/haengdong/application/BillActionDetailService.java new file mode 100644 index 000000000..55d39aac0 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/BillActionDetailService.java @@ -0,0 +1,76 @@ +package server.haengdong.application; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.BillActionDetailUpdateAppRequest; +import server.haengdong.application.request.BillActionDetailsUpdateAppRequest; +import server.haengdong.application.response.BillActionDetailsAppResponse; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class BillActionDetailService { + + private final BillActionRepository billActionRepository; + + public BillActionDetailsAppResponse findBillActionDetails(String token, Long actionId) { + BillAction billAction = billActionRepository.findByAction_Id(actionId) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); + validateToken(token, billAction); + + List<BillActionDetail> billActionDetails = billAction.getBillActionDetails(); + return BillActionDetailsAppResponse.of(billActionDetails); + } + + @Transactional + public void updateBillActionDetails(String token, Long actionId, BillActionDetailsUpdateAppRequest request) { + BillAction billAction = billActionRepository.findByAction_Id(actionId) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); + + List<BillActionDetailUpdateAppRequest> billActionDetailUpdateAppRequests = request.billActionDetailUpdateAppRequests(); + + validateToken(token, billAction); + validateTotalPrice(billActionDetailUpdateAppRequests, billAction); + + List<BillActionDetail> billActionDetails = billAction.getBillActionDetails(); + + for (BillActionDetailUpdateAppRequest updateRequest : billActionDetailUpdateAppRequests) { + BillActionDetail detailToUpdate = billActionDetails.stream() + .filter(detail -> detail.isSameName(updateRequest.name())) + .findFirst() + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_DETAIL_NOT_FOUND)); + + detailToUpdate.updatePrice(updateRequest.price()); + detailToUpdate.updateIsFixed(updateRequest.isFixed()); + } + } + + private void validateToken(String token, BillAction billAction) { + Event event = billAction.getEvent(); + if (event.isTokenMismatch(token)) { + throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND); + } + } + + private void validateTotalPrice(List<BillActionDetailUpdateAppRequest> billActionDetailUpdateAppRequests, + BillAction billAction) { + Long requestsPriceSum = calculateUpdatePriceSum(billActionDetailUpdateAppRequests); + if (!billAction.isSamePrice(requestsPriceSum)) { + throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_PRICE_NOT_MATCHED); + } + } + + private Long calculateUpdatePriceSum(List<BillActionDetailUpdateAppRequest> billActionDetailUpdateAppRequests) { + return billActionDetailUpdateAppRequests.stream() + .map(BillActionDetailUpdateAppRequest::price) + .reduce(0L, Long::sum); + } +} diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java new file mode 100644 index 000000000..dae36a2e7 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -0,0 +1,80 @@ +package server.haengdong.application; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.BillActionAppRequest; +import server.haengdong.application.request.BillActionUpdateAppRequest; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.ActionRepository; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.CurrentMembers; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class BillActionService { + + private final BillActionRepository billActionRepository; + private final MemberActionRepository memberActionRepository; + private final ActionRepository actionRepository; + private final EventRepository eventRepository; + + @Transactional + public void saveAllBillAction(String eventToken, List<BillActionAppRequest> requests) { + Event event = getEvent(eventToken); + Action action = createStartAction(event); + List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event); + CurrentMembers currentMembers = CurrentMembers.of(findMemberActions); + + for (BillActionAppRequest request : requests) { + BillAction billAction = request.toBillAction(action, currentMembers); + billActionRepository.save(billAction); + action = action.next(); + } + } + + private Action createStartAction(Event event) { + return actionRepository.findLastByEvent(event) + .map(Action::next) + .orElse(Action.createFirst(event)); + } + + @Transactional + public void updateBillAction(String token, Long actionId, BillActionUpdateAppRequest request) { + BillAction billAction = billActionRepository.findByAction_Id(actionId) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); + + validateToken(token, billAction); + + billAction.update(request.title(), request.price()); + } + + private void validateToken(String token, BillAction billAction) { + Event event = billAction.getEvent(); + if (event.isTokenMismatch(token)) { + throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND); + } + } + + @Transactional + public void deleteBillAction(String token, Long actionId) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + + billActionRepository.deleteByAction_EventAndActionId(event, actionId); + } + + private Event getEvent(String eventToken) { + return eventRepository.findByToken(eventToken) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + } +} diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java new file mode 100644 index 000000000..834c0e10a --- /dev/null +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -0,0 +1,165 @@ +package server.haengdong.application; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.request.EventLoginAppRequest; +import server.haengdong.application.request.MemberNameUpdateAppRequest; +import server.haengdong.application.request.MemberNamesUpdateAppRequest; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.EventAppResponse; +import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.application.response.MembersAppResponse; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.domain.event.EventTokenProvider; +import server.haengdong.exception.AuthenticationException; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class EventService { + + private final EventRepository eventRepository; + private final EventTokenProvider eventTokenProvider; + private final BillActionRepository billActionRepository; + private final MemberActionRepository memberActionRepository; + + @Transactional + public EventAppResponse saveEvent(EventAppRequest request) { + String token = eventTokenProvider.createToken(); + Event event = request.toEvent(token); + eventRepository.save(event); + + return EventAppResponse.of(event); + } + + public EventDetailAppResponse findEvent(String token) { + Event event = getEvent(token); + + return EventDetailAppResponse.of(event); + } + + public List<ActionAppResponse> findActions(String token) { + Event event = getEvent(token); + + List<BillAction> billActions = billActionRepository.findByAction_Event(event).stream() + .sorted(Comparator.comparing(BillAction::getSequence)).toList(); + List<MemberAction> memberActions = memberActionRepository.findAllByEvent(event).stream() + .sorted(Comparator.comparing(MemberAction::getSequence)).toList(); + + return getActionAppResponses(billActions, memberActions); + } + + private List<ActionAppResponse> getActionAppResponses( + List<BillAction> billActions, + List<MemberAction> memberActions + ) { + int billActionIndex = 0; + int memberActionIndex = 0; + List<ActionAppResponse> actionAppResponses = new ArrayList<>(); + + while (billActionIndex < billActions.size() && memberActionIndex < memberActions.size()) { + BillAction billAction = billActions.get(billActionIndex); + MemberAction memberAction = memberActions.get(memberActionIndex); + if (billAction.getSequence() < memberAction.getSequence()) { + actionAppResponses.add(ActionAppResponse.of(billAction)); + billActionIndex++; + } else { + actionAppResponses.add(ActionAppResponse.of(memberAction)); + memberActionIndex++; + } + } + while (billActionIndex < billActions.size()) { + BillAction billAction = billActions.get(billActionIndex++); + actionAppResponses.add(ActionAppResponse.of(billAction)); + } + while (memberActionIndex < memberActions.size()) { + MemberAction memberAction = memberActions.get(memberActionIndex++); + actionAppResponses.add(ActionAppResponse.of(memberAction)); + } + + return actionAppResponses; + } + + public MembersAppResponse findAllMembers(String token) { + Event event = getEvent(token); + + List<String> memberNames = memberActionRepository.findAllUniqueMemberByEvent(event); + + return new MembersAppResponse(memberNames); + } + + @Transactional + public void updateMember(String token, MemberNamesUpdateAppRequest request) { + Event event = getEvent(token); + List<MemberNameUpdateAppRequest> members = request.members(); + + validateBeforeNames(members, event); + validateAfterNames(members, event); + + members.forEach(member -> updateMemberName(event, member.before(), member.after())); + } + + private void validateBeforeNames(List<MemberNameUpdateAppRequest> members, Event event) { + List<String> beforeNames = members.stream() + .map(MemberNameUpdateAppRequest::before) + .toList(); + if (beforeNames.size() != Set.copyOf(beforeNames).size()) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); + } + beforeNames.forEach(beforeName -> validateBeforeMemberNameExist(event, beforeName)); + } + + private void validateBeforeMemberNameExist(Event event, String beforeName) { + boolean isMemberNameExist = memberActionRepository.existsByAction_EventAndMemberName(event, beforeName); + if (!isMemberNameExist) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NOT_EXIST); + } + } + + private void validateAfterNames(List<MemberNameUpdateAppRequest> members, Event event) { + List<String> afterNames = members.stream() + .map(MemberNameUpdateAppRequest::after) + .toList(); + if (afterNames.size() != Set.copyOf(afterNames).size()) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); + } + afterNames.forEach(afterName -> validateAfterMemberNameNotExist(event, afterName)); + } + + private void validateAfterMemberNameNotExist(Event event, String afterName) { + boolean isMemberNameExist = memberActionRepository.existsByAction_EventAndMemberName(event, afterName); + if (isMemberNameExist) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); + } + } + + private void updateMemberName(Event event, String beforeName, String afterName) { + memberActionRepository.findAllByAction_EventAndMemberName(event, beforeName) + .forEach(memberAction -> memberAction.updateMemberName(afterName)); + } + + public void validatePassword(EventLoginAppRequest request) throws HaengdongException { + Event event = getEvent(request.token()); + if (event.isPasswordMismatch(request.password())) { + throw new AuthenticationException(HaengdongErrorCode.PASSWORD_INVALID); + } + } + + private Event getEvent(String token) { + return eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + } +} diff --git a/server/src/main/java/server/haengdong/application/MemberActionFactory.java b/server/src/main/java/server/haengdong/application/MemberActionFactory.java new file mode 100644 index 000000000..c0a171642 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/MemberActionFactory.java @@ -0,0 +1,62 @@ +package server.haengdong.application; + +import java.util.ArrayList; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.CurrentMembers; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionStatus; +import server.haengdong.domain.action.MemberGroupIdProvider; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Component +public class MemberActionFactory { + + private final MemberGroupIdProvider memberGroupIdProvider; + + public List<MemberAction> createMemberActions( + MemberActionsSaveAppRequest request, + CurrentMembers currentMembers, + Action action + ) { + validateMemberNames(request); + validateActions(request, currentMembers); + + Long memberGroupId = memberGroupIdProvider.createGroupId(); + List<MemberAction> createdMemberActions = new ArrayList<>(); + List<MemberActionSaveAppRequest> actions = request.actions(); + for (MemberActionSaveAppRequest appRequest : actions) { + MemberAction memberAction = appRequest.toMemberAction(action, memberGroupId); + createdMemberActions.add(memberAction); + action = action.next(); + } + + return createdMemberActions; + } + + private void validateMemberNames(MemberActionsSaveAppRequest request) { + List<String> memberNames = request.actions().stream() + .map(MemberActionSaveAppRequest::name) + .toList(); + + long uniqueCount = memberNames.stream().distinct().count(); + if (uniqueCount != memberNames.size()) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); + } + } + + private void validateActions(MemberActionsSaveAppRequest request, CurrentMembers currentMembers) { + List<MemberActionSaveAppRequest> actions = request.actions(); + + for (MemberActionSaveAppRequest action : actions) { + MemberActionStatus memberActionStatus = MemberActionStatus.of(action.status()); + currentMembers.validate(action.name(), memberActionStatus); + } + } +} diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java new file mode 100644 index 000000000..245de8cef --- /dev/null +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -0,0 +1,100 @@ +package server.haengdong.application; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.application.response.CurrentMemberAppResponse; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.ActionRepository; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.CurrentMembers; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class MemberActionService { + + private final MemberActionFactory memberActionFactory; + private final MemberActionRepository memberActionRepository; + private final EventRepository eventRepository; + private final ActionRepository actionRepository; + private final BillActionRepository billActionRepository; + + @Transactional + public void saveMemberAction(String token, MemberActionsSaveAppRequest request) { + Event event = findEvent(token); + + List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event); + CurrentMembers currentMembers = CurrentMembers.of(findMemberActions); + Action action = createStartAction(event); + List<MemberAction> memberActions = memberActionFactory.createMemberActions(request, currentMembers, action); + memberActionRepository.saveAll(memberActions); + } + + private Action createStartAction(Event event) { + return actionRepository.findLastByEvent(event) + .map(Action::next) + .orElse(Action.createFirst(event)); + } + + public List<CurrentMemberAppResponse> getCurrentMembers(String token) { + Event event = findEvent(token); + List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event); + CurrentMembers currentMembers = CurrentMembers.of(findMemberActions); + + return currentMembers.getMembers() + .stream() + .map(CurrentMemberAppResponse::new) + .toList(); + } + + private Event findEvent(String token) { + return eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + } + + @Transactional + public void deleteMember(String token, String memberName) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + + memberActionRepository.deleteAllByEventAndMemberName(event, memberName); + + List<BillAction> billActions = billActionRepository.findByAction_Event(event); + billActions.forEach(billAction -> resetBillAction(event, billAction)); + } + + @Transactional + public void deleteMemberAction(String token, Long actionId) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + Action action = actionRepository.findByIdAndEvent(actionId, event) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.ACTION_NOT_FOUND)); + MemberAction memberAction = memberActionRepository.findByAction(action) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_ACTION_NOT_FOUND)); + + memberActionRepository.deleteAllByMemberNameAndMinSequence(memberAction.getMemberName(), + memberAction.getSequence()); + + List<BillAction> billActions = billActionRepository.findByEventAndGreaterThanSequence(event, + action.getSequence()); + billActions.forEach(billAction -> resetBillAction(event, billAction)); + } + + private void resetBillAction(Event event, BillAction billAction) { + List<MemberAction> memberActions = memberActionRepository.findByEventAndSequence(event, + billAction.getSequence()); + CurrentMembers currentMembers = CurrentMembers.of(memberActions); + + billAction.resetBillActionDetails(currentMembers); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java new file mode 100644 index 000000000..21eb17d4a --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java @@ -0,0 +1,15 @@ +package server.haengdong.application.request; + +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.CurrentMembers; + +public record BillActionAppRequest( + String title, + Long price +) { + + public BillAction toBillAction(Action action, CurrentMembers currentMembers) { + return BillAction.create(action, title, price, currentMembers); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java new file mode 100644 index 000000000..e514aee81 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java @@ -0,0 +1,8 @@ +package server.haengdong.application.request; + +public record BillActionDetailUpdateAppRequest( + String name, + Long price, + boolean isFixed +) { +} diff --git a/server/src/main/java/server/haengdong/application/request/BillActionDetailsUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionDetailsUpdateAppRequest.java new file mode 100644 index 000000000..1fe19798e --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/BillActionDetailsUpdateAppRequest.java @@ -0,0 +1,8 @@ +package server.haengdong.application.request; + +import java.util.List; + +public record BillActionDetailsUpdateAppRequest( + List<BillActionDetailUpdateAppRequest> billActionDetailUpdateAppRequests +) { +} diff --git a/server/src/main/java/server/haengdong/application/request/BillActionUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionUpdateAppRequest.java new file mode 100644 index 000000000..a90e3dd42 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/BillActionUpdateAppRequest.java @@ -0,0 +1,7 @@ +package server.haengdong.application.request; + +public record BillActionUpdateAppRequest( + String title, + Long price +) { +} diff --git a/server/src/main/java/server/haengdong/application/request/EventAppRequest.java b/server/src/main/java/server/haengdong/application/request/EventAppRequest.java new file mode 100644 index 000000000..20ec16d88 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/EventAppRequest.java @@ -0,0 +1,10 @@ +package server.haengdong.application.request; + +import server.haengdong.domain.event.Event; + +public record EventAppRequest(String name, String password) { + + public Event toEvent(String token) { + return new Event(name, password, token); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/EventLoginAppRequest.java b/server/src/main/java/server/haengdong/application/request/EventLoginAppRequest.java new file mode 100644 index 000000000..947b5ef39 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/EventLoginAppRequest.java @@ -0,0 +1,4 @@ +package server.haengdong.application.request; + +public record EventLoginAppRequest(String token, String password) { +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java new file mode 100644 index 000000000..f7f8d8fc2 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java @@ -0,0 +1,12 @@ +package server.haengdong.application.request; + +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionStatus; + +public record MemberActionSaveAppRequest(String name, String status) { + + public MemberAction toMemberAction(Action action, Long memberGroupId) { + return new MemberAction(action, name, MemberActionStatus.of(status), memberGroupId); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java new file mode 100644 index 000000000..650b908df --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java @@ -0,0 +1,6 @@ +package server.haengdong.application.request; + +import java.util.List; + +public record MemberActionsSaveAppRequest(List<MemberActionSaveAppRequest> actions) { +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java new file mode 100644 index 000000000..d629d3a02 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java @@ -0,0 +1,7 @@ +package server.haengdong.application.request; + +public record MemberNameUpdateAppRequest( + String before, + String after +) { +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberNamesUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberNamesUpdateAppRequest.java new file mode 100644 index 000000000..cd0c00544 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberNamesUpdateAppRequest.java @@ -0,0 +1,8 @@ +package server.haengdong.application.request; + +import java.util.List; + +public record MemberNamesUpdateAppRequest( + List<MemberNameUpdateAppRequest> members +) { +} diff --git a/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java b/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java new file mode 100644 index 000000000..0c2c12611 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java @@ -0,0 +1,61 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionStatus; + +public record ActionAppResponse( + Long actionId, + String name, + Long price, + Long sequence, + boolean isFixed, + ActionType actionType +) { + + public ActionAppResponse(Long actionId, String name, Long price, Long sequence, ActionType actionType) { + this(actionId, name, price, sequence, false, actionType); + } + + public static ActionAppResponse of(BillAction billAction) { + return new ActionAppResponse( + billAction.getAction().getId(), + billAction.getTitle(), + billAction.getPrice(), + billAction.getSequence(), + billAction.isFixed(), + ActionAppResponse.ActionType.BILL + ); + } + + public static ActionAppResponse of(MemberAction memberAction) { + MemberActionStatus status = memberAction.getStatus(); + + return new ActionAppResponse( + memberAction.getAction().getId(), + memberAction.getMemberName(), + null, + memberAction.getSequence(), + false, + ActionAppResponse.ActionType.of(status) + ); + } + + public String actionTypeName() { + return actionType.name(); + } + + public enum ActionType { + BILL, + IN, + OUT, + ; + + private static ActionType of(MemberActionStatus memberActionStatus) { + if (MemberActionStatus.IN == memberActionStatus) { + return IN; + } + return OUT; + } + } +} diff --git a/server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java b/server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java new file mode 100644 index 000000000..3efc7ac9d --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java @@ -0,0 +1,18 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.action.BillActionDetail; + +public record BillActionDetailAppResponse( + String name, + Long price, + boolean isFixed +) { + + public static BillActionDetailAppResponse of(BillActionDetail billActionDetail) { + return new BillActionDetailAppResponse( + billActionDetail.getMemberName(), + billActionDetail.getPrice(), + billActionDetail.isFixed() + ); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/BillActionDetailsAppResponse.java b/server/src/main/java/server/haengdong/application/response/BillActionDetailsAppResponse.java new file mode 100644 index 000000000..061f07816 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/BillActionDetailsAppResponse.java @@ -0,0 +1,14 @@ +package server.haengdong.application.response; + +import java.util.List; +import java.util.stream.Collectors; +import server.haengdong.domain.action.BillActionDetail; + +public record BillActionDetailsAppResponse(List<BillActionDetailAppResponse> billActionDetailAppResponses) { + + public static BillActionDetailsAppResponse of(List<BillActionDetail> billActionDetails) { + return billActionDetails.stream() + .map(BillActionDetailAppResponse::of) + .collect(Collectors.collectingAndThen(Collectors.toList(), BillActionDetailsAppResponse::new)); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java b/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java new file mode 100644 index 000000000..6c682d3e9 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.action.MemberAction; + +public record CurrentMemberAppResponse(String name) { + + public static CurrentMemberAppResponse of(MemberAction memberAction) { + return new CurrentMemberAppResponse(memberAction.getMemberName()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/EventAppResponse.java b/server/src/main/java/server/haengdong/application/response/EventAppResponse.java new file mode 100644 index 000000000..f331d0011 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/EventAppResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.event.Event; + +public record EventAppResponse(String token) { + + public static EventAppResponse of(Event event) { + return new EventAppResponse(event.getToken()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java b/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java new file mode 100644 index 000000000..6e38826d4 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.event.Event; + +public record EventDetailAppResponse(String eventName) { + + public static EventDetailAppResponse of(Event event) { + return new EventDetailAppResponse(event.getName()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java b/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java new file mode 100644 index 000000000..21b6cef56 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java @@ -0,0 +1,4 @@ +package server.haengdong.application.response; + +public record MemberBillReportAppResponse(String name, Long price) { +} diff --git a/server/src/main/java/server/haengdong/application/response/MembersAppResponse.java b/server/src/main/java/server/haengdong/application/response/MembersAppResponse.java new file mode 100644 index 000000000..be8378b37 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/MembersAppResponse.java @@ -0,0 +1,8 @@ +package server.haengdong.application.response; + +import java.util.List; + +public record MembersAppResponse( + List<String> memberNames +) { +} diff --git a/server/src/main/java/server/haengdong/config/AdminInterceptor.java b/server/src/main/java/server/haengdong/config/AdminInterceptor.java new file mode 100644 index 000000000..a0542ed46 --- /dev/null +++ b/server/src/main/java/server/haengdong/config/AdminInterceptor.java @@ -0,0 +1,51 @@ +package server.haengdong.config; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpMethod; +import org.springframework.web.servlet.HandlerInterceptor; +import server.haengdong.application.AuthService; +import server.haengdong.exception.AuthenticationException; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.infrastructure.auth.AuthenticationExtractor; + +@Slf4j +public class AdminInterceptor implements HandlerInterceptor { + + private final AuthService authService; + private final AuthenticationExtractor authenticationExtractor; + + public AdminInterceptor(AuthService authService, AuthenticationExtractor authenticationExtractor) { + this.authService = authService; + this.authenticationExtractor = authenticationExtractor; + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + String requestURI = request.getRequestURI(); + + if (requestURI.endsWith("/login")) { + return true; // 요청을 계속 진행하도록 허용 + } + + HttpMethod method = HttpMethod.valueOf(request.getMethod()); + if (HttpMethod.GET.equals(method) || HttpMethod.OPTIONS.equals(method)) { + return true; + } + + validateToken(request); + + return true; + } + + private void validateToken(HttpServletRequest request) { + String token = authenticationExtractor.extract(request, authService.getTokenName()); + String tokenEventId = authService.findEventIdByToken(token); + String eventId = request.getRequestURI().split("/")[3]; + if (!tokenEventId.equals(eventId)) { + log.warn("[행사 접근 불가] Cookie EventId = {}, URL EventId = {}", tokenEventId, eventId); + throw new AuthenticationException(HaengdongErrorCode.FORBIDDEN); + } + } +} diff --git a/server/src/main/java/server/haengdong/config/RequestServletFilter.java b/server/src/main/java/server/haengdong/config/RequestServletFilter.java new file mode 100644 index 000000000..b1afdb6f8 --- /dev/null +++ b/server/src/main/java/server/haengdong/config/RequestServletFilter.java @@ -0,0 +1,23 @@ +package server.haengdong.config; + +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import java.io.IOException; +import org.springframework.stereotype.Component; +import org.springframework.web.util.ContentCachingRequestWrapper; + +@Component +public class RequestServletFilter implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper((HttpServletRequest) request); + + chain.doFilter(wrappedRequest, response); + } +} diff --git a/server/src/main/java/server/haengdong/config/WebMvcConfig.java b/server/src/main/java/server/haengdong/config/WebMvcConfig.java new file mode 100644 index 000000000..d1caa176f --- /dev/null +++ b/server/src/main/java/server/haengdong/config/WebMvcConfig.java @@ -0,0 +1,66 @@ +package server.haengdong.config; + +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import server.haengdong.application.AuthService; +import server.haengdong.domain.TokenProvider; +import server.haengdong.infrastructure.auth.AuthenticationExtractor; +import server.haengdong.infrastructure.auth.JwtTokenProvider; +import server.haengdong.infrastructure.auth.TokenProperties; + +@RequiredArgsConstructor +@EnableConfigurationProperties(TokenProperties.class) +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + + private final TokenProperties tokenProperties; + + @Value("${cors.max-age}") + private Long maxAge; + + @Value("${cors.allowed-origins}") + private String[] allowedOrigins; + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOrigins(allowedOrigins) + .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS") + .allowedHeaders("*") + .allowCredentials(true) + .maxAge(maxAge); + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(adminInterceptor()) + .addPathPatterns("/api/**") + .excludePathPatterns("/api/events"); + } + + @Bean + public AdminInterceptor adminInterceptor() { + return new AdminInterceptor(authService(), authenticationExtractor()); + } + + @Bean + public AuthService authService() { + return new AuthService(tokenProvider()); + } + + @Bean + public TokenProvider tokenProvider() { + return new JwtTokenProvider(tokenProperties); + } + + @Bean + public AuthenticationExtractor authenticationExtractor() { + return new AuthenticationExtractor(); + } +} diff --git a/server/src/main/java/server/haengdong/domain/TokenProvider.java b/server/src/main/java/server/haengdong/domain/TokenProvider.java new file mode 100644 index 000000000..28e7956c3 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/TokenProvider.java @@ -0,0 +1,12 @@ +package server.haengdong.domain; + +import java.util.Map; + +public interface TokenProvider { + + String createToken(Map<String, Object> payload); + + Map<String, Object> getPayload(String token); + + boolean validateToken(String token); +} diff --git a/server/src/main/java/server/haengdong/domain/action/Action.java b/server/src/main/java/server/haengdong/domain/action/Action.java new file mode 100644 index 000000000..11f91fc38 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/Action.java @@ -0,0 +1,42 @@ +package server.haengdong.domain.action; + +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import server.haengdong.domain.event.Event; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class Action { + + private static final long FIRST_SEQUENCE = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + private Event event; + + private Long sequence; + + public Action(Event event, Long sequence) { + this.event = event; + this.sequence = sequence; + } + + public static Action createFirst(Event event) { + return new Action(event, FIRST_SEQUENCE); + } + + public Action next() { + return new Action(event, sequence + 1); + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/ActionRepository.java b/server/src/main/java/server/haengdong/domain/action/ActionRepository.java new file mode 100644 index 000000000..2fde0ffa6 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/ActionRepository.java @@ -0,0 +1,23 @@ +package server.haengdong.domain.action; + +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.event.Event; + +@Repository +public interface ActionRepository extends JpaRepository<Action, Long> { + + @Query(""" + SELECT a + FROM Action a + WHERE a.event = :event + ORDER BY a.sequence DESC + LIMIT 1 + """) + Optional<Action> findLastByEvent(@Param("event") Event event); + + Optional<Action> findByIdAndEvent(Long id, Event event); +} diff --git a/server/src/main/java/server/haengdong/domain/action/BillAction.java b/server/src/main/java/server/haengdong/domain/action/BillAction.java new file mode 100644 index 000000000..943b40ce5 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/BillAction.java @@ -0,0 +1,156 @@ +package server.haengdong.domain.action; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import server.haengdong.domain.event.Event; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class BillAction implements Comparable<BillAction> { + + public static final int MIN_TITLE_LENGTH = 1; + public static final int MAX_TITLE_LENGTH = 30; + public static final long MIN_PRICE = 1L; + public static final long MAX_PRICE = 10_000_000L; + private static final long DEFAULT_PRICE = 0L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) + private Action action; + + @Column(length = MAX_TITLE_LENGTH) + private String title; + + private Long price; + + @OneToMany(mappedBy = "billAction", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) + private List<BillActionDetail> billActionDetails = new ArrayList<>(); + + public BillAction(Action action, String title, Long price) { + validateTitle(title); + validatePrice(price); + this.action = action; + this.title = title.trim(); + this.price = price; + } + + private void validateTitle(String title) { + int titleLength = title.trim().length(); + if (titleLength < MIN_TITLE_LENGTH || titleLength > MAX_TITLE_LENGTH) { + throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_TITLE_INVALID); + } + } + + private void validatePrice(Long price) { + if (price < MIN_PRICE || price > MAX_PRICE) { + throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_PRICE_INVALID); + } + } + + public static BillAction create(Action action, String title, Long price, CurrentMembers currentMembers) { + BillAction billAction = new BillAction(action, title, price); + billAction.resetBillActionDetails(currentMembers); + return billAction; + } + + public void resetBillActionDetails(CurrentMembers currentMembers) { + this.billActionDetails.clear(); + Iterator<Long> priceIterator = distributePrice(currentMembers.size()).iterator(); + + for (String member : currentMembers.getMembers()) { + BillActionDetail billActionDetail = new BillActionDetail(this, member, priceIterator.next(), false); + this.billActionDetails.add(billActionDetail); + } + } + + private void resetBillActionDetails() { + Iterator<Long> priceIterator = distributePrice(billActionDetails.size()).iterator(); + + billActionDetails.forEach(billActionDetail -> { + billActionDetail.updatePrice(priceIterator.next()); + billActionDetail.updateIsFixed(false); + }); + } + + private List<Long> distributePrice(int memberCount) { + if (memberCount == 0) { + return new ArrayList<>(); + } + long eachPrice = price / memberCount; + long remainder = price % memberCount; + + List<Long> results = Stream.generate(() -> eachPrice) + .limit(memberCount - 1) + .collect(Collectors.toList()); + results.add(eachPrice + remainder); + return results; + } + + public void update(String title, Long price) { + validateTitle(title); + validatePrice(price); + this.title = title.trim(); + this.price = price; + resetBillActionDetails(); + } + + public void addDetails(List<BillActionDetail> billActionDetails) { + billActionDetails.forEach(this::addDetail); + } + + private void addDetail(BillActionDetail billActionDetail) { + this.billActionDetails.add(billActionDetail); + billActionDetail.setBillAction(this); + } + + public boolean isFixed() { + return billActionDetails.stream() + .anyMatch(BillActionDetail::isFixed); + } + + public boolean isSamePrice(Long price) { + return this.price.equals(price); + } + + public Long findPriceByMemberName(String memberName) { + return billActionDetails.stream() + .filter(billActionDetail -> billActionDetail.hasMemberName(memberName)) + .map(BillActionDetail::getPrice) + .findFirst() + .orElse(DEFAULT_PRICE); + } + + public Long getSequence() { + return action.getSequence(); + } + + public Event getEvent() { + return action.getEvent(); + } + + @Override + public int compareTo(BillAction o) { + return Long.compare(this.getSequence(), o.getSequence()); + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java new file mode 100644 index 000000000..ad13e6ab2 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java @@ -0,0 +1,57 @@ +package server.haengdong.domain.action; + +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class BillActionDetail { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + private BillAction billAction; + + private String memberName; + + private Long price; + + private boolean isFixed; + + public BillActionDetail(BillAction billAction, String memberName, Long price, boolean isFixed) { + this.billAction = billAction; + this.memberName = memberName; + this.price = price; + this.isFixed = isFixed; + } + + public void updatePrice(Long price) { + this.price = price; + } + + public void updateIsFixed(boolean isFixed) { + this.isFixed = isFixed; + } + + public boolean hasMemberName(String memberName) { + return this.memberName.equals(memberName); + } + + public boolean isSameName(String memberName) { + return this.memberName.equals(memberName); + } + + public void setBillAction(BillAction billAction) { + this.billAction = billAction; + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java new file mode 100644 index 000000000..d1d7cfe0f --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java @@ -0,0 +1,17 @@ +package server.haengdong.domain.action; + +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +@Repository +public interface BillActionDetailRepository extends JpaRepository<BillActionDetail, Long> { + + @Query(""" + select bd + from BillActionDetail bd + where bd.billAction = :billAction + """) + List<BillActionDetail> findAllByBillAction(BillAction billAction); +} diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java new file mode 100644 index 000000000..817a63bf8 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java @@ -0,0 +1,27 @@ +package server.haengdong.domain.action; + +import java.util.List; +import java.util.Optional; +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.event.Event; + +@Repository +public interface BillActionRepository extends JpaRepository<BillAction, Long> { + + @EntityGraph(attributePaths = {"action"}) + List<BillAction> findByAction_Event(Event event); + + void deleteByAction_EventAndActionId(Event event, Long actionId); + + Optional<BillAction> findByAction_Id(Long actionId); + + @Query(""" + select ba + from BillAction ba + where ba.action.event = :event and ba.action.sequence > :sequence + """) + List<BillAction> findByEventAndGreaterThanSequence(Event event, Long sequence); +} diff --git a/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java b/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java new file mode 100644 index 000000000..ba380aae5 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java @@ -0,0 +1,81 @@ +package server.haengdong.domain.action; + +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +public class CurrentMembers { + + private final Set<String> members; + + public CurrentMembers() { + this(new HashSet<>()); + } + + protected CurrentMembers(Set<String> members) { + this.members = members; + } + + public static CurrentMembers of(List<MemberAction> memberActions) { + List<MemberAction> sortedMemberActions = getSortedMemberActions(memberActions); + Set<String> members = new HashSet<>(); + for (MemberAction memberAction : sortedMemberActions) { + String member = memberAction.getMemberName(); + if (memberAction.isSameStatus(MemberActionStatus.IN)) { + members.add(member); + continue; + } + members.remove(member); + } + + return new CurrentMembers(members); + } + + private static List<MemberAction> getSortedMemberActions(List<MemberAction> memberActions) { + return memberActions.stream() + .sorted(Comparator.comparing(MemberAction::getSequence)) + .toList(); + } + + public CurrentMembers addMemberAction(MemberAction memberAction) { + String memberName = memberAction.getMemberName(); + + Set<String> currentMembers = new HashSet<>(members); + + if (memberAction.isIn()) { + currentMembers.add(memberName); + } else { + currentMembers.remove(memberName); + } + return new CurrentMembers(currentMembers); + } + + public void validate(String memberName, MemberActionStatus memberActionStatus) { + if (memberActionStatus == MemberActionStatus.IN && members.contains(memberName)) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_ALREADY_EXIST); + } + if (memberActionStatus == MemberActionStatus.OUT && !members.contains(memberName)) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NOT_EXIST); + } + } + + public boolean isEmpty() { + return members.isEmpty(); + } + + public boolean isNotEmpty() { + return !members.isEmpty(); + } + + public int size() { + return members.size(); + } + + public Set<String> getMembers() { + return Collections.unmodifiableSet(members); + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberAction.java b/server/src/main/java/server/haengdong/domain/action/MemberAction.java new file mode 100644 index 000000000..3faf65bde --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/MemberAction.java @@ -0,0 +1,76 @@ +package server.haengdong.domain.action; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToOne; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class MemberAction implements Comparable<MemberAction> { + + public static final int MIN_NAME_LENGTH = 1; + public static final int MAX_NAME_LENGTH = 4; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) + private Action action; + + private String memberName; + + @Enumerated(EnumType.STRING) + private MemberActionStatus status; + + private Long memberGroupId; + + public MemberAction(Action action, String memberName, MemberActionStatus status, Long memberGroupId) { + validateMemberName(memberName); + this.action = action; + this.memberName = memberName; + this.status = status; + this.memberGroupId = memberGroupId; + } + + private void validateMemberName(String memberName) { + int memberLength = memberName.length(); + if (memberLength < MIN_NAME_LENGTH || memberLength > MAX_NAME_LENGTH) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_LENGTH_INVALID); + } + } + + public void updateMemberName(String memberName) { + validateMemberName(memberName); + this.memberName = memberName; + } + + public boolean isIn() { + return status == MemberActionStatus.IN; + } + + public boolean isSameStatus(MemberActionStatus memberActionStatus) { + return status == memberActionStatus; + } + + public Long getSequence() { + return action.getSequence(); + } + + @Override + public int compareTo(MemberAction o) { + return Long.compare(this.getSequence(), o.getSequence()); + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java new file mode 100644 index 000000000..324ff9797 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java @@ -0,0 +1,53 @@ +package server.haengdong.domain.action; + +import java.util.List; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.event.Event; + +@Repository +public interface MemberActionRepository extends JpaRepository<MemberAction, Long> { + + @Query("select m from MemberAction m join fetch m.action where m.action.event = :event") + List<MemberAction> findAllByEvent(@Param("event") Event event); + + @Query(""" + select distinct m.memberName + from MemberAction m + where m.action.event = :event + """) + List<String> findAllUniqueMemberByEvent(Event event); + + @Modifying + @Query(""" + delete + from MemberAction m + where m.memberName = :memberName and m.action.event = :event + """) + void deleteAllByEventAndMemberName(Event event, String memberName); + + Optional<MemberAction> findByAction(Action action); + + @Modifying + @Query(""" + delete + from MemberAction m + where m.memberName = :memberName and m.action.sequence >= :sequence + """) + void deleteAllByMemberNameAndMinSequence(String memberName, Long sequence); + + List<MemberAction> findAllByAction_EventAndMemberName(Event event, String memberName); + + boolean existsByAction_EventAndMemberName(Event event, String updatedMemberName); + + @Query(""" + select ma + from MemberAction ma + where ma.action.event = :event and ma.action.sequence < :sequence + """) + List<MemberAction> findByEventAndSequence(Event event, Long sequence); +} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java b/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java new file mode 100644 index 000000000..76c5a66d4 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java @@ -0,0 +1,19 @@ +package server.haengdong.domain.action; + +import java.util.Arrays; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +public enum MemberActionStatus { + IN, + OUT, + ; + + public static MemberActionStatus of(String status) { + return Arrays.stream(MemberActionStatus.values()) + .filter(s -> s.name().equals(status)) + .findFirst() + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_ACTION_STATUS_INVALID, + String.format(HaengdongErrorCode.MEMBER_ACTION_STATUS_INVALID.getMessage(), status))); + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java b/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java new file mode 100644 index 000000000..7a707b9d8 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java @@ -0,0 +1,75 @@ +package server.haengdong.domain.action; + +import static java.util.stream.Collectors.toMap; + +import java.util.List; +import java.util.Map; +import java.util.PriorityQueue; +import java.util.function.Function; +import lombok.Getter; + +@Getter +public class MemberBillReport { + + private final Map<String, Long> reports; + + private MemberBillReport(Map<String, Long> reports) { + this.reports = reports; + } + + public static MemberBillReport createByActions(List<BillAction> billActions, List<MemberAction> memberActions) { + PriorityQueue<BillAction> sortedBillActions = new PriorityQueue<>(billActions); + PriorityQueue<MemberAction> sortedMemberActions = new PriorityQueue<>(memberActions); + + Map<String, Long> memberBillReports = initReports(memberActions); + CurrentMembers currentMembers = new CurrentMembers(); + while (!sortedBillActions.isEmpty() && !sortedMemberActions.isEmpty()) { + if (isMemberActionTurn(sortedMemberActions, sortedBillActions)) { + MemberAction memberAction = sortedMemberActions.poll(); + currentMembers = currentMembers.addMemberAction(memberAction); + continue; + } + addBillAction(sortedBillActions, currentMembers, memberBillReports); + } + + while (!sortedBillActions.isEmpty()) { + addBillAction(sortedBillActions, currentMembers, memberBillReports); + } + + return new MemberBillReport(memberBillReports); + } + + private static Map<String, Long> initReports(List<MemberAction> memberActions) { + return memberActions.stream() + .map(MemberAction::getMemberName) + .distinct() + .collect(toMap(Function.identity(), i -> 0L)); + } + + private static boolean isMemberActionTurn( + PriorityQueue<MemberAction> memberActions, + PriorityQueue<BillAction> billActions + ) { + MemberAction memberAction = memberActions.peek(); + BillAction billAction = billActions.peek(); + + return memberAction.getSequence() < billAction.getSequence(); + } + + private static void addBillAction( + PriorityQueue<BillAction> sortedBillActions, + CurrentMembers currentMembers, + Map<String, Long> memberBillReports + ) { + BillAction billAction = sortedBillActions.poll(); + if (currentMembers.isEmpty()) { + return; + } + + for (String currentMember : currentMembers.getMembers()) { + Long currentPrice = billAction.findPriceByMemberName(currentMember); + Long price = memberBillReports.get(currentMember) + currentPrice; + memberBillReports.put(currentMember, price); + } + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java b/server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java new file mode 100644 index 000000000..9e32bd733 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java @@ -0,0 +1,11 @@ +package server.haengdong.domain.action; + +import org.springframework.stereotype.Component; + +@Component +public class MemberGroupIdProvider { + + public Long createGroupId() { + return System.currentTimeMillis(); + } +} diff --git a/server/src/main/java/server/haengdong/domain/event/Event.java b/server/src/main/java/server/haengdong/domain/event/Event.java new file mode 100644 index 000000000..bb5d53dbc --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/Event.java @@ -0,0 +1,70 @@ +package server.haengdong.domain.event; + +import jakarta.persistence.AttributeOverride; +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class Event { + + public static final int MIN_NAME_LENGTH = 1; + public static final int MAX_NAME_LENGTH = 20; + private static final String SPACES = " "; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String name; + + @Embedded + @AttributeOverride(name = "value", column = @Column(name = "password")) + private Password password; + + private String token; + + public Event(String name, String password, String token) { + validateName(name); + this.name = name; + this.password = new Password(password); + this.token = token; + } + + private void validateName(String name) { + int nameLength = name.trim().length(); + if (nameLength < MIN_NAME_LENGTH || MAX_NAME_LENGTH < nameLength) { + throw new HaengdongException(HaengdongErrorCode.EVENT_NAME_LENGTH_INVALID, + String.format("행사 이름은 %d자 이상 %d자 이하만 입력 가능합니다. 입력한 이름 길이 : %d", + MIN_NAME_LENGTH, + MAX_NAME_LENGTH, + name.length())); + } + if (isBlankContinuous(name)) { + throw new HaengdongException(HaengdongErrorCode.EVENT_NAME_CONSECUTIVE_SPACES, + String.format("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s", name)); + } + } + + private boolean isBlankContinuous(String name) { + return name.contains(SPACES); + } + + public boolean isTokenMismatch(String token) { + return !this.token.equals(token); + } + + public boolean isPasswordMismatch(String rawPassword) { + return !password.matches(rawPassword); + } +} diff --git a/server/src/main/java/server/haengdong/domain/event/EventRepository.java b/server/src/main/java/server/haengdong/domain/event/EventRepository.java new file mode 100644 index 000000000..09526125e --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/EventRepository.java @@ -0,0 +1,11 @@ +package server.haengdong.domain.event; + +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface EventRepository extends JpaRepository<Event, Long> { + + Optional<Event> findByToken(String token); +} diff --git a/server/src/main/java/server/haengdong/domain/event/EventStep.java b/server/src/main/java/server/haengdong/domain/event/EventStep.java new file mode 100644 index 000000000..297abdb66 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/EventStep.java @@ -0,0 +1,28 @@ +package server.haengdong.domain.event; + +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class EventStep { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + private Event event; + + private String name; + + private Long sequence; +} diff --git a/server/src/main/java/server/haengdong/domain/event/EventTokenProvider.java b/server/src/main/java/server/haengdong/domain/event/EventTokenProvider.java new file mode 100644 index 000000000..6450f0dcf --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/EventTokenProvider.java @@ -0,0 +1,12 @@ +package server.haengdong.domain.event; + +import java.util.UUID; +import org.springframework.stereotype.Component; + +@Component +public class EventTokenProvider { + + public String createToken() { + return UUID.randomUUID().toString(); + } +} diff --git a/server/src/main/java/server/haengdong/domain/event/Password.java b/server/src/main/java/server/haengdong/domain/event/Password.java new file mode 100644 index 000000000..375849dbf --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/Password.java @@ -0,0 +1,52 @@ +package server.haengdong.domain.event; + +import jakarta.persistence.Embeddable; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter +@Embeddable +public class Password { + + public static final int PASSWORD_LENGTH = 4; + private static final Pattern PASSWORD_PATTERN = Pattern.compile(String.format("^\\d{%d}$", PASSWORD_LENGTH)); + private static final String HASH_ALGORITHM = "SHA-256"; + + private String value; + + public Password(String password) { + validatePassword(password); + this.value = encode(password); + } + + private void validatePassword(String password) { + Matcher matcher = PASSWORD_PATTERN.matcher(password); + if (!matcher.matches()) { + throw new HaengdongException(HaengdongErrorCode.EVENT_PASSWORD_FORMAT_INVALID); + } + } + + private String encode(String rawPassword) { + try { + MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM); + byte[] hashedPassword = digest.digest(rawPassword.getBytes()); + return Base64.getEncoder().encodeToString(hashedPassword); + } catch (NoSuchAlgorithmException e) { + throw new IllegalArgumentException("해시 알고리즘이 존재하지 않습니다."); + } + } + + public boolean matches(String rawPassword) { + String hashedPassword = encode(rawPassword); + return value.equals(hashedPassword); + } +} diff --git a/server/src/main/java/server/haengdong/exception/AuthenticationException.java b/server/src/main/java/server/haengdong/exception/AuthenticationException.java new file mode 100644 index 000000000..2efcb16e7 --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/AuthenticationException.java @@ -0,0 +1,19 @@ +package server.haengdong.exception; + +import lombok.Getter; + +@Getter +public class AuthenticationException extends RuntimeException { + + private final HaengdongErrorCode errorCode; + private final String message; + + public AuthenticationException(HaengdongErrorCode errorCode) { + this(errorCode, errorCode.getMessage()); + } + + public AuthenticationException(HaengdongErrorCode errorCode, String message) { + this.errorCode = errorCode; + this.message = message; + } +} diff --git a/server/src/main/java/server/haengdong/exception/ErrorResponse.java b/server/src/main/java/server/haengdong/exception/ErrorResponse.java new file mode 100644 index 000000000..d0a2b01a0 --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/ErrorResponse.java @@ -0,0 +1,15 @@ +package server.haengdong.exception; + +public record ErrorResponse( + HaengdongErrorCode errorCode, + String message +) { + + public static ErrorResponse of(HaengdongErrorCode errorCode) { + return new ErrorResponse(errorCode, errorCode.getMessage()); + } + + public static ErrorResponse of(HaengdongErrorCode errorCode, String message) { + return new ErrorResponse(errorCode, message); + } +} diff --git a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java new file mode 100644 index 000000000..0cee7cb4c --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java @@ -0,0 +1,90 @@ +package server.haengdong.exception; + +import jakarta.servlet.http.HttpServletRequest; +import java.io.BufferedReader; +import java.io.IOException; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.resource.NoResourceFoundException; + +@Slf4j +@RestControllerAdvice +public class GlobalExceptionHandler { + + private static final String LOG_FORMAT = """ + \n\t{ + "RequestURI": "{} {}", + "RequestBody": {}, + "ErrorMessage": "{}" + \t} + """; + + @ExceptionHandler(AuthenticationException.class) + public ResponseEntity<ErrorResponse> authenticationException(HttpServletRequest req, AuthenticationException e) { + log.warn(LOG_FORMAT, req.getMethod(), req.getRequestURI(), getRequestBody(req), e.getMessage(), e); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED) + .body(ErrorResponse.of(e.getErrorCode())); + } + + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + public ResponseEntity<ErrorResponse> noResourceException(HttpRequestMethodNotSupportedException e) { + log.warn(e.getMessage(), e); + return ResponseEntity.badRequest() + .body(ErrorResponse.of(HaengdongErrorCode.REQUEST_METHOD_NOT_SUPPORTED)); + } + + @ExceptionHandler(NoResourceFoundException.class) + public ResponseEntity<ErrorResponse> noResourceException(NoResourceFoundException e) { + log.warn(e.getMessage(), e); + return ResponseEntity.badRequest() + .body(ErrorResponse.of(HaengdongErrorCode.NO_RESOURCE_REQUEST)); + } + + @ExceptionHandler(HttpMessageNotReadableException.class) + public ResponseEntity<ErrorResponse> httpMessageNotReadableException(HttpMessageNotReadableException e) { + log.warn(e.getMessage(), e); + return ResponseEntity.badRequest() + .body(ErrorResponse.of(HaengdongErrorCode.MESSAGE_NOT_READABLE)); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity<ErrorResponse> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { + log.warn(e.getMessage(), e); + String errorMessage = e.getFieldErrors().stream() + .map(error -> error.getField() + " " + error.getDefaultMessage()) + .collect(Collectors.joining(", ")); + + return ResponseEntity.badRequest() + .body(ErrorResponse.of(HaengdongErrorCode.REQUEST_EMPTY, errorMessage)); + } + + @ExceptionHandler(HaengdongException.class) + public ResponseEntity<ErrorResponse> haengdongException(HttpServletRequest req, HaengdongException e) { + log.warn(LOG_FORMAT, req.getMethod(), req.getRequestURI(), getRequestBody(req), e.getMessage(), e); + return ResponseEntity.badRequest() + .body(ErrorResponse.of(e.getErrorCode())); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity<ErrorResponse> handleException(HttpServletRequest req, Exception e) { + log.error(LOG_FORMAT, req.getMethod(), req.getRequestURI(), getRequestBody(req), e.getMessage(), e); + return ResponseEntity.internalServerError() + .body(ErrorResponse.of(HaengdongErrorCode.INTERNAL_SERVER_ERROR)); + } + + private String getRequestBody(HttpServletRequest req) { + try (BufferedReader reader = req.getReader()) { + return reader.lines().collect(Collectors.joining(System.lineSeparator() + "\t")); + } catch (IOException e) { + log.error("Failed to read request body", e); + return ""; + } + } +} diff --git a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java new file mode 100644 index 000000000..475d16c11 --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java @@ -0,0 +1,69 @@ +package server.haengdong.exception; + +import lombok.Getter; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.Password; + +@Getter +public enum HaengdongErrorCode { + + /* Domain */ + + EVENT_NOT_FOUND("존재하지 않는 행사입니다."), + EVENT_NAME_LENGTH_INVALID(String.format("행사 이름은 %d자 이상 %d자 이하만 입력 가능합니다.", + Event.MIN_NAME_LENGTH, + Event.MAX_NAME_LENGTH)), + EVENT_NAME_CONSECUTIVE_SPACES("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s"), + EVENT_PASSWORD_FORMAT_INVALID(String.format("비밀번호는 %d자리 숫자만 가능합니다.", Password.PASSWORD_LENGTH)), + + ACTION_NOT_FOUND("존재하지 않는 액션입니다."), + + MEMBER_NAME_LENGTH_INVALID(String.format("멤버 이름은 %d자 이상 %d자 이하만 입력 가능합니다.", + MemberAction.MIN_NAME_LENGTH, + MemberAction.MAX_NAME_LENGTH)), + MEMBER_NAME_DUPLICATE("중복된 행사 참여 인원 이름이 존재합니다."), + MEMBER_NOT_EXIST("현재 참여하고 있지 않는 인원이 존재합니다."), + MEMBER_ALREADY_EXIST("현재 참여하고 있는 인원이 존재합니다."), + MEMBER_NAME_CHANGE_DUPLICATE("중복된 참여 인원 이름 변경 요청이 존재합니다."), + + MEMBER_ACTION_NOT_FOUND("존재하지 않는 멤버 액션입니다."), + MEMBER_ACTION_STATUS_INVALID("멤버 액션은 IN, OUT만 가능합니다. 입력한 멤버 액션: %s"), + + BILL_ACTION_NOT_FOUND("존재하지 않는 지출 액션입니다."), + BILL_ACTION_TITLE_INVALID(String.format("앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다.", + BillAction.MIN_TITLE_LENGTH, + BillAction.MAX_TITLE_LENGTH)), + BILL_ACTION_PRICE_INVALID(String.format("지출 금액은 %,d 이하의 자연수여야 합니다.", BillAction.MAX_PRICE)), + BILL_ACTION_DETAIL_NOT_FOUND("존재하지 않는 참여자 지출입니다."), + BILL_ACTION_PRICE_NOT_MATCHED("지출 총액이 일치하지 않습니다."), + + /* Authentication */ + + PASSWORD_INVALID("비밀번호가 일치하지 않습니다."), + + TOKEN_NOT_FOUND("토큰이 존재하지 않습니다."), + TOKEN_EXPIRED("만료된 토큰입니다."), + TOKEN_INVALID("유효하지 않은 토큰입니다."), + + FORBIDDEN("접근할 수 없는 행사입니다."), + + /* Request Validation */ + + REQUEST_EMPTY("입력 값은 공백일 수 없습니다.") + + /* System */, + + MESSAGE_NOT_READABLE("읽을 수 없는 요청입니다."), + REQUEST_METHOD_NOT_SUPPORTED("지원하지 않는 요청 메서드입니다."), + NO_RESOURCE_REQUEST("존재하지 않는 자원입니다."), + INTERNAL_SERVER_ERROR("서버 내부에서 에러가 발생했습니다."), + ; + + private final String message; + + HaengdongErrorCode(String message) { + this.message = message; + } +} diff --git a/server/src/main/java/server/haengdong/exception/HaengdongException.java b/server/src/main/java/server/haengdong/exception/HaengdongException.java new file mode 100644 index 000000000..b86fe4ffc --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/HaengdongException.java @@ -0,0 +1,19 @@ +package server.haengdong.exception; + +import lombok.Getter; + +@Getter +public class HaengdongException extends RuntimeException { + + private final HaengdongErrorCode errorCode; + private final String message; + + public HaengdongException(HaengdongErrorCode errorCode) { + this(errorCode, errorCode.getMessage()); + } + + public HaengdongException(HaengdongErrorCode errorCode, String message) { + this.errorCode = errorCode; + this.message = message; + } +} diff --git a/server/src/main/java/server/haengdong/infrastructure/auth/AuthenticationExtractor.java b/server/src/main/java/server/haengdong/infrastructure/auth/AuthenticationExtractor.java new file mode 100644 index 000000000..4972de48a --- /dev/null +++ b/server/src/main/java/server/haengdong/infrastructure/auth/AuthenticationExtractor.java @@ -0,0 +1,23 @@ +package server.haengdong.infrastructure.auth; + +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import java.util.Arrays; +import server.haengdong.exception.AuthenticationException; +import server.haengdong.exception.HaengdongErrorCode; + +public class AuthenticationExtractor { + + public String extract(HttpServletRequest request, String cookieName) { + Cookie[] cookies = request.getCookies(); + if (cookies == null) { + throw new AuthenticationException(HaengdongErrorCode.TOKEN_NOT_FOUND); + } + + return Arrays.stream(cookies) + .filter(cookie -> cookieName.equals(cookie.getName())) + .findFirst() + .orElseThrow(() -> new AuthenticationException(HaengdongErrorCode.TOKEN_NOT_FOUND)) + .getValue(); + } +} diff --git a/server/src/main/java/server/haengdong/infrastructure/auth/CookieProperties.java b/server/src/main/java/server/haengdong/infrastructure/auth/CookieProperties.java new file mode 100644 index 000000000..18f867601 --- /dev/null +++ b/server/src/main/java/server/haengdong/infrastructure/auth/CookieProperties.java @@ -0,0 +1,15 @@ +package server.haengdong.infrastructure.auth; + +import java.time.Duration; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties("cookie") +public record CookieProperties( + boolean httpOnly, + boolean secure, + String domain, + String path, + String sameSite, + Duration maxAge +) { +} diff --git a/server/src/main/java/server/haengdong/infrastructure/auth/JwtTokenProvider.java b/server/src/main/java/server/haengdong/infrastructure/auth/JwtTokenProvider.java new file mode 100644 index 000000000..df9ec6a81 --- /dev/null +++ b/server/src/main/java/server/haengdong/infrastructure/auth/JwtTokenProvider.java @@ -0,0 +1,54 @@ +package server.haengdong.infrastructure.auth; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jws; +import io.jsonwebtoken.JwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import server.haengdong.domain.TokenProvider; + +public class JwtTokenProvider implements TokenProvider { + + private final TokenProperties tokenProperties; + + public JwtTokenProvider(TokenProperties tokenProperties) { + this.tokenProperties = tokenProperties; + } + + @Override + public String createToken(Map<String, Object> payload) { + Claims claims = Jwts.claims(new HashMap<>(payload)); + Date now = new Date(); + Date validity = new Date(now.getTime() + tokenProperties.expireLength()); + + return Jwts.builder() + .setClaims(claims) + .setIssuedAt(now) + .setExpiration(validity) + .signWith(SignatureAlgorithm.HS256, tokenProperties.secretKey()) + .compact(); + } + + @Override + public Map<String, Object> getPayload(String token) { + return Jwts.parser() + .setSigningKey(tokenProperties.secretKey()) + .parseClaimsJws(token) + .getBody(); + } + + @Override + public boolean validateToken(String token) { + try { + Jws<Claims> claims = Jwts.parser().setSigningKey(tokenProperties.secretKey()).parseClaimsJws(token); + + return !claims.getBody().getExpiration().before(new Date()); + } catch (JwtException | IllegalArgumentException e) { + return false; + } + } +} + diff --git a/server/src/main/java/server/haengdong/infrastructure/auth/TokenProperties.java b/server/src/main/java/server/haengdong/infrastructure/auth/TokenProperties.java new file mode 100644 index 000000000..11dedcdbf --- /dev/null +++ b/server/src/main/java/server/haengdong/infrastructure/auth/TokenProperties.java @@ -0,0 +1,7 @@ +package server.haengdong.infrastructure.auth; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties("security.jwt.token") +public record TokenProperties(String secretKey, Long expireLength) { +} diff --git a/server/src/main/java/server/haengdong/presentation/ActionController.java b/server/src/main/java/server/haengdong/presentation/ActionController.java new file mode 100644 index 000000000..657cb567e --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/ActionController.java @@ -0,0 +1,26 @@ +package server.haengdong.presentation; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.ActionService; +import server.haengdong.application.response.MemberBillReportAppResponse; +import server.haengdong.presentation.response.MemberBillReportsResponse; + +@RequiredArgsConstructor +@RestController +public class ActionController { + + private final ActionService actionService; + + @GetMapping("/api/events/{eventId}/actions/reports") + public ResponseEntity<MemberBillReportsResponse> getMemberBillReports(@PathVariable("eventId") String token) { + List<MemberBillReportAppResponse> memberBillReports = actionService.getMemberBillReports(token); + + return ResponseEntity.ok() + .body(MemberBillReportsResponse.of(memberBillReports)); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/BillActionController.java b/server/src/main/java/server/haengdong/presentation/BillActionController.java new file mode 100644 index 000000000..56e99337d --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/BillActionController.java @@ -0,0 +1,55 @@ +package server.haengdong.presentation; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.BillActionService; +import server.haengdong.presentation.request.BillActionUpdateRequest; +import server.haengdong.presentation.request.BillActionsSaveRequest; + +@RequiredArgsConstructor +@RestController +public class BillActionController { + + private final BillActionService billActionService; + + @PostMapping("/api/events/{eventId}/bill-actions") + public ResponseEntity<Void> saveAllBillAction( + @PathVariable("eventId") String token, + @Valid @RequestBody BillActionsSaveRequest request + ) { + billActionService.saveAllBillAction(token, request.toAppRequests()); + + return ResponseEntity.ok() + .build(); + } + + @PutMapping("/api/events/{eventId}/bill-actions/{actionId}") + public ResponseEntity<Void> updateBillAction( + @PathVariable("eventId") String token, + @PathVariable("actionId") Long actionId, + @Valid @RequestBody BillActionUpdateRequest request + ) { + billActionService.updateBillAction(token, actionId, request.toAppResponse()); + + return ResponseEntity.ok() + .build(); + } + + @DeleteMapping("/api/events/{eventId}/bill-actions/{actionId}") + public ResponseEntity<Void> deleteBillAction( + @PathVariable("eventId") String token, + @PathVariable("actionId") Long actionId + ) { + billActionService.deleteBillAction(token, actionId); + + return ResponseEntity.ok() + .build(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java b/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java new file mode 100644 index 000000000..5602e6777 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java @@ -0,0 +1,42 @@ +package server.haengdong.presentation; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.BillActionDetailService; +import server.haengdong.application.response.BillActionDetailsAppResponse; +import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; +import server.haengdong.presentation.response.BillActionDetailsResponse; + +@RequiredArgsConstructor +@RestController +public class BillActionDetailController { + + private final BillActionDetailService billActionDetailService; + + @GetMapping("/api/events/{eventId}/bill-actions/{actionId}/fixed") + public ResponseEntity<BillActionDetailsResponse> findBillActionDetails( + @PathVariable("eventId") String token, + @PathVariable("actionId") Long actionId + ) { + BillActionDetailsAppResponse appResponse = billActionDetailService.findBillActionDetails(token, actionId); + + return ResponseEntity.ok(BillActionDetailsResponse.of(appResponse)); + } + + @PutMapping("/api/events/{eventId}/bill-actions/{actionId}/fixed") + public ResponseEntity<Void> updateBillActionDetails( + @PathVariable("eventId") String token, + @PathVariable("actionId") Long actionId, + @Valid @RequestBody BillActionDetailsUpdateRequest request + ) { + billActionDetailService.updateBillActionDetails(token, actionId, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java new file mode 100644 index 000000000..34261042f --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -0,0 +1,120 @@ +package server.haengdong.presentation; + +import jakarta.validation.Valid; +import java.util.List; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseCookie; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.AuthService; +import server.haengdong.application.EventService; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.infrastructure.auth.CookieProperties; +import server.haengdong.presentation.request.EventLoginRequest; +import server.haengdong.presentation.request.EventSaveRequest; +import server.haengdong.presentation.request.MemberNamesUpdateRequest; +import server.haengdong.presentation.response.ActionsResponse; +import server.haengdong.presentation.response.EventDetailResponse; +import server.haengdong.presentation.response.EventResponse; +import server.haengdong.presentation.response.MembersResponse; +import server.haengdong.presentation.response.StepsResponse; + +@Slf4j +@RequiredArgsConstructor +@EnableConfigurationProperties(CookieProperties.class) +@RestController +public class EventController { + + private final EventService eventService; + private final AuthService authService; + private final CookieProperties cookieProperties; + + @PostMapping("/api/events") + public ResponseEntity<EventResponse> saveEvent(@Valid @RequestBody EventSaveRequest request) { + EventResponse eventResponse = EventResponse.of(eventService.saveEvent(request.toAppRequest())); + + String jwtToken = authService.createToken(eventResponse.eventId()); + + ResponseCookie responseCookie = createResponseCookie(jwtToken); + return ResponseEntity.ok() + .header(HttpHeaders.SET_COOKIE, responseCookie.toString()) + .body(eventResponse); + } + + @GetMapping("/api/events/{eventId}") + public ResponseEntity<EventDetailResponse> findEvent(@PathVariable("eventId") String token) { + EventDetailResponse eventDetailResponse = EventDetailResponse.of(eventService.findEvent(token)); + + return ResponseEntity.ok(eventDetailResponse); + } + + @GetMapping("/api/events/{eventId}/actions") + public ResponseEntity<StepsResponse> findActions(@PathVariable("eventId") String token) { + StepsResponse stepsResponse = StepsResponse.of(eventService.findActions(token)); + + return ResponseEntity.ok(stepsResponse); + } + + @GetMapping("/api/events/{eventId}/actions/v2") + public ResponseEntity<ActionsResponse> findActions2(@PathVariable("eventId") String token) { + List<ActionAppResponse> actions = eventService.findActions(token); + ActionsResponse actionsResponse = ActionsResponse.of(actions); + + return ResponseEntity.ok(actionsResponse); + } + + @GetMapping("/api/events/{eventId}/members") + public ResponseEntity<MembersResponse> findAllMembers(@PathVariable("eventId") String token) { + MembersResponse response = MembersResponse.of(eventService.findAllMembers(token)); + + return ResponseEntity.ok(response); + } + + @PutMapping("/api/events/{eventId}/members/nameChange") + public ResponseEntity<Void> updateMember( + @PathVariable("eventId") String token, + @Valid @RequestBody MemberNamesUpdateRequest request + ) { + eventService.updateMember(token, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } + + @PostMapping("/api/events/{eventId}/login") + public ResponseEntity<Void> loginEvent( + @PathVariable("eventId") String token, + @Valid @RequestBody EventLoginRequest request + ) { + eventService.validatePassword(request.toAppRequest(token)); + String jwtToken = authService.createToken(token); + + ResponseCookie responseCookie = createResponseCookie(jwtToken); + return ResponseEntity.ok() + .header(HttpHeaders.SET_COOKIE, responseCookie.toString()) + .build(); + } + + @PostMapping("/api/events/{eventId}/auth") + public ResponseEntity<Void> authenticate(@PathVariable("eventId") String token) { + return ResponseEntity.ok().build(); + } + + private ResponseCookie createResponseCookie(String token) { + return ResponseCookie.from(authService.getTokenName(), token) + .httpOnly(cookieProperties.httpOnly()) + .secure(cookieProperties.secure()) + .domain(cookieProperties.domain()) + .path(cookieProperties.path()) + .sameSite(cookieProperties.sameSite()) + .maxAge(cookieProperties.maxAge()) + .build(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/MemberActionController.java b/server/src/main/java/server/haengdong/presentation/MemberActionController.java new file mode 100644 index 000000000..1703245f7 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/MemberActionController.java @@ -0,0 +1,60 @@ +package server.haengdong.presentation; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.MemberActionService; +import server.haengdong.application.response.CurrentMemberAppResponse; +import server.haengdong.presentation.request.MemberActionsSaveRequest; +import server.haengdong.presentation.response.CurrentMembersResponse; + +@RequiredArgsConstructor +@RestController +public class MemberActionController { + + private final MemberActionService memberActionService; + + @PostMapping("/api/events/{eventId}/member-actions") + public ResponseEntity<Void> saveMemberAction( + @PathVariable("eventId") String token, + @RequestBody MemberActionsSaveRequest request + ) { + memberActionService.saveMemberAction(token, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } + + @GetMapping("/api/events/{eventId}/members/current") + public ResponseEntity<CurrentMembersResponse> getCurrentMembers(@PathVariable("eventId") String token) { + List<CurrentMemberAppResponse> currentMembers = memberActionService.getCurrentMembers(token); + + return ResponseEntity.ok() + .body(CurrentMembersResponse.of(currentMembers)); + } + + @DeleteMapping("/api/events/{eventId}/members/{memberName}") + public ResponseEntity<Void> deleteMember( + @PathVariable("eventId") String token, + @PathVariable("memberName") String memberName + ) { + memberActionService.deleteMember(token, memberName); + + return ResponseEntity.ok().build(); + } + + @DeleteMapping("/api/events/{eventId}/member-actions/{actionId}") + public ResponseEntity<Void> deleteMemberAction( + @PathVariable("eventId") String token, + @PathVariable("actionId") Long actionId + ) { + memberActionService.deleteMemberAction(token, actionId); + + return ResponseEntity.ok().build(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java new file mode 100644 index 000000000..21c4bd60f --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java @@ -0,0 +1,21 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import server.haengdong.application.request.BillActionDetailUpdateAppRequest; + +public record BillActionDetailUpdateRequest( + + @NotBlank(message = "맴버 이름은 공백일 수 없습니다.") + String name, + + @NotNull(message = "지출 금액은 공백일 수 없습니다.") + Long price, + + @NotNull(message = "지출 금액은 공백일 수 없습니다.") + boolean isFixed +) { + public BillActionDetailUpdateAppRequest toAppRequest() { + return new BillActionDetailUpdateAppRequest(this.name, this.price, this.isFixed); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java new file mode 100644 index 000000000..fafbb8fd7 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java @@ -0,0 +1,16 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import java.util.List; +import server.haengdong.application.request.BillActionDetailsUpdateAppRequest; + +public record BillActionDetailsUpdateRequest( + @Valid @NotEmpty List<BillActionDetailUpdateRequest> members +) { + public BillActionDetailsUpdateAppRequest toAppRequest() { + return new BillActionDetailsUpdateAppRequest(members.stream() + .map(BillActionDetailUpdateRequest::toAppRequest) + .toList()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java new file mode 100644 index 000000000..a47ff8316 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java @@ -0,0 +1,19 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import server.haengdong.application.request.BillActionAppRequest; + +public record BillActionSaveRequest( + + @NotBlank(message = "지출 내역 제목은 공백일 수 없습니다.") + String title, + + @NotNull(message = "지출 금액은 공백일 수 없습니다.") + Long price +) { + + public BillActionAppRequest toAppRequest() { + return new BillActionAppRequest(title, price); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java new file mode 100644 index 000000000..680006816 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java @@ -0,0 +1,18 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import server.haengdong.application.request.BillActionUpdateAppRequest; + +public record BillActionUpdateRequest( + + @NotBlank(message = "지출 내역 제목은 공백일 수 없습니다.") + String title, + + @NotNull(message = "지출 금액은 공백일 수 없습니다.") + Long price +) { + public BillActionUpdateAppRequest toAppResponse() { + return new BillActionUpdateAppRequest(title, price); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java new file mode 100644 index 000000000..6727d4cf1 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java @@ -0,0 +1,18 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import java.util.List; +import server.haengdong.application.request.BillActionAppRequest; + +public record BillActionsSaveRequest( + + @Valid @NotEmpty List<BillActionSaveRequest> actions +) { + + public List<BillActionAppRequest> toAppRequests() { + return actions.stream() + .map(BillActionSaveRequest::toAppRequest) + .toList(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/EventLoginRequest.java b/server/src/main/java/server/haengdong/presentation/request/EventLoginRequest.java new file mode 100644 index 000000000..a1286e903 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/EventLoginRequest.java @@ -0,0 +1,14 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import server.haengdong.application.request.EventLoginAppRequest; + +public record EventLoginRequest( + + @NotBlank(message = "비밀번호는 공백일 수 없습니다.") + String password +) { + public EventLoginAppRequest toAppRequest(String token) { + return new EventLoginAppRequest(token, password); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java new file mode 100644 index 000000000..6bd7cd006 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java @@ -0,0 +1,18 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import server.haengdong.application.request.EventAppRequest; + +public record EventSaveRequest( + + @NotBlank(message = "행사 이름은 공백일 수 없습니다.") + String eventName, + + @NotBlank(message = "비밀번호는 공백일 수 없습니다.") + String password +) { + + public EventAppRequest toAppRequest() { + return new EventAppRequest(eventName, password); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java new file mode 100644 index 000000000..41e95cc3c --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java @@ -0,0 +1,25 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import java.util.List; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; + +public record MemberActionsSaveRequest( + + @NotEmpty + List<String> members, + + @NotBlank(message = "멤버 액션은 공백일 수 없습니다.") + String status +) { + + public MemberActionsSaveAppRequest toAppRequest() { + List<MemberActionSaveAppRequest> appRequests = members.stream() + .map(name -> new MemberActionSaveAppRequest(name, status)) + .toList(); + + return new MemberActionsSaveAppRequest(appRequests); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberNameUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberNameUpdateRequest.java new file mode 100644 index 000000000..3cd2294ca --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MemberNameUpdateRequest.java @@ -0,0 +1,18 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import server.haengdong.application.request.MemberNameUpdateAppRequest; + +public record MemberNameUpdateRequest( + + @NotBlank(message = "멤버 이름은 공백일 수 없습니다.") + String before, + + @NotBlank(message = "멤버 이름은 공백일 수 없습니다.") + String after +) { + + public MemberNameUpdateAppRequest toAppRequest() { + return new MemberNameUpdateAppRequest(before, after); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java new file mode 100644 index 000000000..872aa55de --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java @@ -0,0 +1,17 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import java.util.List; +import server.haengdong.application.request.MemberNamesUpdateAppRequest; + +public record MemberNamesUpdateRequest( + @Valid @NotEmpty List<MemberNameUpdateRequest> members +) { + + public MemberNamesUpdateAppRequest toAppRequest() { + return new MemberNamesUpdateAppRequest(members.stream() + .map(MemberNameUpdateRequest::toAppRequest) + .toList()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java b/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java new file mode 100644 index 000000000..ea26ea769 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java @@ -0,0 +1,26 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.ActionAppResponse; + +public record ActionResponse( + Long actionId, + String name, + Long price, + Long sequence, + boolean isFixed +) { + + public ActionResponse(Long actionId, String name, Long price, Long sequence) { + this(actionId, name, price, sequence, false); + } + + public static ActionResponse of(ActionAppResponse actionAppResponse) { + return new ActionResponse( + actionAppResponse.actionId(), + actionAppResponse.name(), + actionAppResponse.price(), + actionAppResponse.sequence(), + actionAppResponse.isFixed() + ); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java b/server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java new file mode 100644 index 000000000..ea46c5bd9 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java @@ -0,0 +1,22 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.ActionAppResponse; + +public record ActionResponse2( + Long actionId, + String name, + Long price, + Long sequence, + String type +) { + + public static ActionResponse2 of(ActionAppResponse actionAppResponse) { + return new ActionResponse2( + actionAppResponse.actionId(), + actionAppResponse.name(), + actionAppResponse.price(), + actionAppResponse.sequence(), + actionAppResponse.actionType().name() + ); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java b/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java new file mode 100644 index 000000000..c8ae780e3 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java @@ -0,0 +1,14 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import server.haengdong.application.response.ActionAppResponse; + +public record ActionsResponse( + List<ActionResponse2> actions +) { + public static ActionsResponse of(List<ActionAppResponse> actions) { + return new ActionsResponse(actions.stream() + .map(ActionResponse2::of) + .toList()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java b/server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java new file mode 100644 index 000000000..10f71b82e --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java @@ -0,0 +1,18 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.BillActionDetailAppResponse; + +public record BillActionDetailResponse( + String name, + Long price, + boolean isFixed +) { + + public static BillActionDetailResponse of(BillActionDetailAppResponse billActionDetailAppResponse) { + return new BillActionDetailResponse( + billActionDetailAppResponse.name(), + billActionDetailAppResponse.price(), + billActionDetailAppResponse.isFixed() + ); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/BillActionDetailsResponse.java b/server/src/main/java/server/haengdong/presentation/response/BillActionDetailsResponse.java new file mode 100644 index 000000000..182e76db6 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/BillActionDetailsResponse.java @@ -0,0 +1,16 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import java.util.stream.Collectors; +import server.haengdong.application.response.BillActionDetailsAppResponse; + +public record BillActionDetailsResponse( + List<BillActionDetailResponse> members +) { + + public static BillActionDetailsResponse of(BillActionDetailsAppResponse billActionDetailsAppResponse) { + return billActionDetailsAppResponse.billActionDetailAppResponses().stream() + .map(BillActionDetailResponse::of) + .collect(Collectors.collectingAndThen(Collectors.toList(), BillActionDetailsResponse::new)); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java b/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java new file mode 100644 index 000000000..289cca4fa --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java @@ -0,0 +1,15 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import server.haengdong.application.response.CurrentMemberAppResponse; + +public record CurrentMembersResponse(List<String> memberNames) { + + public static CurrentMembersResponse of(List<CurrentMemberAppResponse> currentMembers) { + List<String> responses = currentMembers.stream() + .map(CurrentMemberAppResponse::name) + .toList(); + + return new CurrentMembersResponse(responses); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java b/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java new file mode 100644 index 000000000..c18694393 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.EventDetailAppResponse; + +public record EventDetailResponse(String eventName) { + + public static EventDetailResponse of(EventDetailAppResponse response) { + return new EventDetailResponse(response.eventName()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/EventResponse.java b/server/src/main/java/server/haengdong/presentation/response/EventResponse.java new file mode 100644 index 000000000..506f5e814 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/EventResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.EventAppResponse; + +public record EventResponse(String eventId) { + + public static EventResponse of(EventAppResponse eventAppResponse) { + return new EventResponse(eventAppResponse.token()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java new file mode 100644 index 000000000..0ea409202 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.MemberBillReportAppResponse; + +public record MemberBillReportResponse(String name, Long price) { + + public static MemberBillReportResponse of(MemberBillReportAppResponse memberBillReportAppResponse) { + return new MemberBillReportResponse(memberBillReportAppResponse.name(), memberBillReportAppResponse.price()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java new file mode 100644 index 000000000..d350c4009 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java @@ -0,0 +1,15 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import server.haengdong.application.response.MemberBillReportAppResponse; + +public record MemberBillReportsResponse(List<MemberBillReportResponse> reports) { + + public static MemberBillReportsResponse of(List<MemberBillReportAppResponse> memberBillReports) { + List<MemberBillReportResponse> reports = memberBillReports.stream() + .map(MemberBillReportResponse::of) + .toList(); + + return new MemberBillReportsResponse(reports); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/MembersResponse.java b/server/src/main/java/server/haengdong/presentation/response/MembersResponse.java new file mode 100644 index 000000000..0947d9e02 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/MembersResponse.java @@ -0,0 +1,13 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import server.haengdong.application.response.MembersAppResponse; + +public record MembersResponse( + List<String> memberNames +) { + + public static MembersResponse of(MembersAppResponse response) { + return new MembersResponse(response.memberNames()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/StepResponse.java b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java new file mode 100644 index 000000000..55dd62c58 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java @@ -0,0 +1,27 @@ +package server.haengdong.presentation.response; + +import java.util.ArrayList; +import java.util.List; +import server.haengdong.application.response.ActionAppResponse; + +public record StepResponse( + String stepName, + String type, + List<String> members, + List<ActionResponse> actions +) { + public static StepResponse of(String stepName, List<String> members, List<ActionAppResponse> actions) { + return new StepResponse( + stepName, + actions.get(0).actionTypeName(), + new ArrayList<>(members), + toActionsResponse(actions) + ); + } + + private static List<ActionResponse> toActionsResponse(List<ActionAppResponse> actions) { + return actions.stream() + .map(ActionResponse::of) + .toList(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java b/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java new file mode 100644 index 000000000..5f7573d67 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java @@ -0,0 +1,56 @@ +package server.haengdong.presentation.response; + +import java.util.ArrayList; +import java.util.List; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.ActionAppResponse.ActionType; + +public record StepsResponse(List<StepResponse> steps) { + + public static StepsResponse of(List<ActionAppResponse> actions) { + List<StepResponse> steps = new ArrayList<>(); + List<String> currentMembers = new ArrayList<>(); + List<List<ActionAppResponse>> groups = createGroups(actions); + + int billStepCount = 0; + for (List<ActionAppResponse> group : groups) { + changeCurrentMembers(group, currentMembers); + if (group.get(0).actionType() == ActionType.BILL) { + billStepCount++; + } + StepResponse stepResponse = StepResponse.of(billStepCount + "차", currentMembers, group); + steps.add(stepResponse); + } + return new StepsResponse(steps); + } + + private static List<List<ActionAppResponse>> createGroups(List<ActionAppResponse> actions) { + List<List<ActionAppResponse>> groups = new ArrayList<>(); + + for (ActionAppResponse action : actions) { + if (groups.isEmpty() || isActionTypeChange(action, groups)) { + groups.add(new ArrayList<>()); + } + groups.get(groups.size() - 1).add(action); + } + + return groups; + } + + private static boolean isActionTypeChange(ActionAppResponse action, List<List<ActionAppResponse>> groups) { + List<ActionAppResponse> currentGroup = groups.get(groups.size() - 1); + return currentGroup.get(0).actionType() != action.actionType(); + } + + private static void changeCurrentMembers(List<ActionAppResponse> group, List<String> currentMembers) { + for (ActionAppResponse action : group) { + if (action.actionType() == ActionType.IN) { + currentMembers.add(action.name()); + continue; + } + if (action.actionType() == ActionType.OUT) { + currentMembers.remove(action.name()); + } + } + } +} diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml new file mode 100644 index 000000000..2ae503547 --- /dev/null +++ b/server/src/main/resources/application.yml @@ -0,0 +1,66 @@ +spring: + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:mem:database + username: sa + password: + + h2: + console: + enabled: true + path: /h2-console + + jpa: + hibernate: + ddl-auto: create + properties: + hibernate: + format_sql: true + jdbc.time_zone: Asia/Seoul + show-sql: true + +cors: + max-age: 3600 + allowed-origins: http://localhost:3000, https://haengdong.pro, https://dev.haengdong.pro, https://app.haengdong.pro + +security: + jwt: + token: + secret-key: skdmeejEKJdkDjklDlkj123DKLJ3kDkeDkDKQMEOD1D90D8dE + expire-length: 604800000 # 1주일 + +cookie: + http-only: false + secure: false + path: / + same-site: none + max-age: 7D + +management: + endpoints: + web: + exposure: + include: health, metrics, logfile + +server: + servlet: + encoding: + charset: UTF-8 + enabled: true + force: true + +--- + +spring: + config: + import: classpath:config/application-prod.yml + activate: + on-profile: prod + +--- + +spring: + config: + import: classpath:config/application-dev.yml + activate: + on-profile: dev diff --git a/server/src/main/resources/config b/server/src/main/resources/config new file mode 160000 index 000000000..fa4270674 --- /dev/null +++ b/server/src/main/resources/config @@ -0,0 +1 @@ +Subproject commit fa42706743e6eb3f4fd8c34618614eff8ae94b3d diff --git a/server/src/main/resources/logback-spring.xml b/server/src/main/resources/logback-spring.xml new file mode 100644 index 000000000..283b966a3 --- /dev/null +++ b/server/src/main/resources/logback-spring.xml @@ -0,0 +1,97 @@ +<configuration> + <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <!-- 콘솔에 로그 출력 형식 --> + <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <appender name="ERROR-ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>ERROR</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + <file>logs/spring-boot-application-error.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>logs/spring-boot-application-error.%d{yyyy-MM-dd}.log</fileNamePattern> + <maxHistory>30</maxHistory> + </rollingPolicy> + <encoder> + <!-- 날짜, 시간, 로그 레벨, 스레드 이름, 로거 이름, 메시지 형식 --> + <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <appender name="WARN-ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>WARN</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + <file>logs/spring-boot-application-warn.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>logs/spring-boot-application-warn.%d{yyyy-MM-dd}.log</fileNamePattern> + <maxHistory>30</maxHistory> + </rollingPolicy> + <encoder> + <!-- 날짜, 시간, 로그 레벨, 스레드 이름, 로거 이름, 메시지 형식 --> + <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <appender name="INFO-ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>INFO</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + <file>logs/spring-boot-application-info.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>logs/spring-boot-application-info.%d{yyyy-MM-dd}.log</fileNamePattern> + <maxHistory>30</maxHistory> + </rollingPolicy> + <encoder> + <!-- 날짜, 시간, 로그 레벨, 스레드 이름, 로거 이름, 메시지 형식 --> + <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <appender name="DEBUG-ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>DEBUG</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + <file>logs/spring-boot-application-debug.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>logs/spring-boot-application-debug.%d{yyyy-MM-dd}.log</fileNamePattern> + <maxHistory>30</maxHistory> + </rollingPolicy> + <encoder> + <!-- 날짜, 시간, 로그 레벨, 스레드 이름, 로거 이름, 메시지 형식 --> + <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <springProfile name="default"> + <root level="INFO"> + <appender-ref ref="CONSOLE"/> + </root> + </springProfile> + + <springProfile name="dev"> + <root level="INFO"> + <appender-ref ref="ERROR-ROLLING"/> + <appender-ref ref="WARN-ROLLING"/> + <appender-ref ref="INFO-ROLLING"/> + <appender-ref ref="DEBUG-ROLLING"/> + </root> + </springProfile> + + <springProfile name="prod"> + <root level="ERROR"> + <appender-ref ref="ERROR-ROLLING"/> + </root> + </springProfile> +</configuration> diff --git a/server/src/test/java/server/haengdong/application/ActionServiceTest.java b/server/src/test/java/server/haengdong/application/ActionServiceTest.java new file mode 100644 index 000000000..ee979b278 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/ActionServiceTest.java @@ -0,0 +1,91 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; +import static server.haengdong.support.fixture.Fixture.BILL_ACTION; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import server.haengdong.application.response.MemberBillReportAppResponse; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class ActionServiceTest extends ServiceTestSupport { + + @Autowired + private ActionService actionService; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillActionRepository billActionRepository; + + @Autowired + private MemberActionRepository memberActionRepository; + + @DisplayName("참여자별 정산 현황을 조회한다.") + @Test + void getMemberBillReports() { + Event event = Fixture.EVENT1; + Event savedEvent = eventRepository.save(event); + List<MemberAction> memberActions = List.of( + new MemberAction(new Action(savedEvent, 1L), "소하", IN, 1L), + new MemberAction(new Action(savedEvent, 2L), "감자", IN, 1L), + new MemberAction(new Action(savedEvent, 3L), "쿠키", IN, 1L), + new MemberAction(new Action(savedEvent, 5L), "감자", OUT, 2L) + ); + List<BillAction> billActions = List.of( + new BillAction(new Action(savedEvent, 4L), "뽕족", 60_000L), + new BillAction(new Action(savedEvent, 7L), "인생네컷", 20_000L) + ); + billActions.get(0).addDetails( + List.of( + new BillActionDetail(BILL_ACTION, "소하", 10_000L, false), + new BillActionDetail(BILL_ACTION, "감자", 40_000L, true), + new BillActionDetail(BILL_ACTION, "쿠키", 10_000L, false) + ) + ); + billActions.get(1).addDetails( + List.of( + new BillActionDetail(BILL_ACTION, "소하", 5_000L, true), + new BillActionDetail(BILL_ACTION, "쿠키", 15_000L, true) + ) + ); + memberActionRepository.saveAll(memberActions); + billActionRepository.saveAll(billActions); + + List<MemberBillReportAppResponse> responses = actionService.getMemberBillReports(event.getToken()); + + assertThat(responses) + .hasSize(3) + .extracting(MemberBillReportAppResponse::name, MemberBillReportAppResponse::price) + .containsExactlyInAnyOrder( + tuple("감자", 40_000L), + tuple("쿠키", 25_000L), + tuple("소하", 15_000L) + ); + } + + @DisplayName("존재하지 않는 이벤트의 참여자별 정산 현황을 조회하는 경우 예외가 발생한다.") + @Test + void getMemberBillReports1() { + assertThatThrownBy(() -> actionService.getMemberBillReports("invalid token")) + .isInstanceOf(HaengdongException.class) + .hasMessage(HaengdongErrorCode.EVENT_NOT_FOUND.getMessage()); + } +} diff --git a/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java new file mode 100644 index 000000000..7074ce846 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java @@ -0,0 +1,111 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.tuple; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import server.haengdong.application.request.BillActionDetailUpdateAppRequest; +import server.haengdong.application.request.BillActionDetailsUpdateAppRequest; +import server.haengdong.application.response.BillActionDetailAppResponse; +import server.haengdong.application.response.BillActionDetailsAppResponse; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; +import server.haengdong.domain.action.BillActionDetailRepository; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class BillActionDetailServiceTest extends ServiceTestSupport { + + @Autowired + private BillActionDetailService billActionDetailService; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillActionRepository billActionRepository; + + @Autowired + private BillActionDetailRepository billActionDetailRepository; + + @DisplayName("참여자별 지출 금액을 조회한다.") + @Test + void findBillActionDetailsTest() { + Event event1 = Fixture.EVENT1; + eventRepository.save(event1); + Action action = new Action(event1, 1L); + BillAction billAction = new BillAction(action, "뽕족", 10000L); + billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "토다리", 6000L, true); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "쿠키", 4000L, true); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); + + BillActionDetailsAppResponse response = billActionDetailService.findBillActionDetails( + event1.getToken(), action.getId()); + + assertThat(response.billActionDetailAppResponses()).hasSize(2) + .extracting(BillActionDetailAppResponse::name, BillActionDetailAppResponse::price) + .containsExactly( + tuple("토다리", 6000L), + tuple("쿠키", 4000L) + ); + } + + @DisplayName("지출 금액 수정 요청의 총합이 지출 금액과 일치하지 않으면 예외가 발생한다.") + @Test + void updateBillActionDetailsTest1() { + Event event1 = Fixture.EVENT1; + eventRepository.save(event1); + Action action = new Action(event1, 1L); + BillAction billAction = new BillAction(action, "뽕족", 10000L); + billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "토다리", 5000L, false); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "쿠키", 5000L, false); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); + + BillActionDetailsUpdateAppRequest request = new BillActionDetailsUpdateAppRequest(List.of( + new BillActionDetailUpdateAppRequest("토다리", 3000L, true), + new BillActionDetailUpdateAppRequest("쿠키", 4000L, true) + )); + assertThatCode( + () -> billActionDetailService.updateBillActionDetails(event1.getToken(), action.getId(), request)) + .isInstanceOf(HaengdongException.class) + .hasMessage("지출 총액이 일치하지 않습니다."); + } + + @DisplayName("지출 고정 금액을 수정한다.") + @Test + void updateBillActionDetailsTest2() { + Event event1 = Fixture.EVENT1; + eventRepository.save(event1); + Action action = new Action(event1, 1L); + BillAction billAction = new BillAction(action, "뽕족", 10000L); + billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "토다리", 5000L, false); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "쿠키", 5000L, false); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); + + BillActionDetailsUpdateAppRequest request = new BillActionDetailsUpdateAppRequest(List.of( + new BillActionDetailUpdateAppRequest("토다리", 3000L, true), + new BillActionDetailUpdateAppRequest("쿠키", 7000L, true) + )); + billActionDetailService.updateBillActionDetails(event1.getToken(), action.getId(), request); + + List<BillActionDetail> results = billActionDetailRepository.findAll(); + + assertThat(results).hasSize(2) + .extracting(BillActionDetail::getMemberName, BillActionDetail::getPrice) + .containsExactly( + tuple("토다리", 3000L), + tuple("쿠키", 7000L) + ); + } +} diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java new file mode 100644 index 000000000..39e52f80c --- /dev/null +++ b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java @@ -0,0 +1,229 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; +import static org.junit.jupiter.api.Assertions.assertAll; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import server.haengdong.application.request.BillActionAppRequest; +import server.haengdong.application.request.BillActionUpdateAppRequest; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; +import server.haengdong.domain.action.BillActionDetailRepository; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.action.MemberActionStatus; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class BillActionServiceTest extends ServiceTestSupport { + + @Autowired + private BillActionService billActionService; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillActionRepository billActionRepository; + + @Autowired + private BillActionDetailRepository billActionDetailRepository; + + @Autowired + private MemberActionRepository memberActionRepository; + + @DisplayName("지출 내역을 생성한다.") + @Test + void saveAllBillAction() { + Event event = Fixture.EVENT1; + Event savedEvent = eventRepository.save(event); + Action action1 = new Action(event, 1L); + Action action2 = new Action(event, 2L); + MemberAction memberAction1 = new MemberAction(action1, "백호", MemberActionStatus.IN, 1L); + MemberAction memberAction2 = new MemberAction(action2, "망쵸", MemberActionStatus.IN, 2L); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); + + List<BillActionAppRequest> requests = List.of( + new BillActionAppRequest("뽕족", 10_000L), + new BillActionAppRequest("인생맥주", 15_000L) + ); + + billActionService.saveAllBillAction(event.getToken(), requests); + + List<BillAction> actions = billActionRepository.findByAction_Event(savedEvent); + + assertThat(actions).extracting(BillAction::getTitle, BillAction::getPrice, BillAction::getSequence) + .containsExactlyInAnyOrder( + tuple("뽕족", 10_000L, 3L), + tuple("인생맥주", 15_000L, 4L) + ); + } + + @DisplayName("지출 내역을 생성하면 지출 상세 내역이 생성된다.") + @Test + void saveAllBillActionTest1() { + Event event = Fixture.EVENT1; + Event savedEvent = eventRepository.save(event); + Action action1 = new Action(event, 1L); + Action action2 = new Action(event, 2L); + MemberAction memberAction1 = new MemberAction(action1, "백호", MemberActionStatus.IN, 1L); + MemberAction memberAction2 = new MemberAction(action2, "망쵸", MemberActionStatus.IN, 2L); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); + + List<BillActionAppRequest> request = List.of( + new BillActionAppRequest("뽕족", 10_000L), + new BillActionAppRequest("인생맥주", 15_000L) + ); + + billActionService.saveAllBillAction(event.getToken(), request); + + List<BillActionDetail> billActionDetails = billActionDetailRepository.findAll(); + + assertThat(billActionDetails) + .hasSize(4) + .extracting("memberName", "price") + .containsExactlyInAnyOrder( + tuple("백호", 5_000L), + tuple("망쵸", 5_000L), + tuple("백호", 7_500L), + tuple("망쵸", 7_500L) + ); + } + + @DisplayName("이벤트가 존재하지 않으면 지출 내역을 생성할 수 없다.") + @Test + void saveAllBillAction1() { + List<BillActionAppRequest> requests = List.of( + new BillActionAppRequest("뽕족", 10_000L), + new BillActionAppRequest("인생맥주", 15_000L) + ); + + assertThatThrownBy(() -> billActionService.saveAllBillAction("token", requests)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("지출 액션을 수정한다.") + @Test + void updateBillAction() { + Event event = Fixture.EVENT1; + Event savedEvent = eventRepository.save(event); + Action action = Action.createFirst(savedEvent); + BillAction billAction = new BillAction(action, "뽕족", 10_000L); + BillAction savedBillAction = billActionRepository.save(billAction); + + Long actionId = savedBillAction.getAction().getId(); + BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L); + + billActionService.updateBillAction(event.getToken(), actionId, request); + + BillAction updatedBillAction = billActionRepository.findById(savedBillAction.getId()).get(); + + assertAll( + () -> assertThat(updatedBillAction.getTitle()).isEqualTo("인생맥주"), + () -> assertThat(updatedBillAction.getPrice()).isEqualTo(20_000L) + ); + } + + @DisplayName("행사에 속하지 않은 지출 액션은 수정할 수 없다.") + @Test + void updateBillAction1() { + Event event1 = Fixture.EVENT1; + Event event2 = Fixture.EVENT2; + Event savedEvent1 = eventRepository.save(event1); + Event savedEvent2 = eventRepository.save(event2); + Action action1 = Action.createFirst(savedEvent1); + Action action2 = Action.createFirst(savedEvent2); + BillAction billAction1 = new BillAction(action1, "뽕족", 10_000L); + BillAction billAction2 = new BillAction(action2, "뽕족", 10_000L); + BillAction savedBillAction1 = billActionRepository.save(billAction1); + billActionRepository.save(billAction2); + + Long actionId = savedBillAction1.getAction().getId(); + BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L); + + assertThatThrownBy(() -> billActionService.updateBillAction(event2.getToken(), actionId, request)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("지출 내역 금액을 변경하면 지출 디테일이 초기화 된다.") + @Test + void updateBillAction2() { + Event event = Fixture.EVENT1; + Event savedEvent = eventRepository.save(event); + Action action = Action.createFirst(savedEvent); + BillAction billAction = new BillAction(action, "뽕족", 10_000L); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "감자", 3000L, true); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "고구마", 2000L, true); + BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "당근", 3000L, true); + BillActionDetail billActionDetail4 = new BillActionDetail(billAction, "양파", 2000L, true); + billAction.addDetails(List.of(billActionDetail1, billActionDetail2, billActionDetail3, billActionDetail4)); + BillAction savedBillAction = billActionRepository.save(billAction); + + Long actionId = savedBillAction.getAction().getId(); + BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L); + + billActionService.updateBillAction(event.getToken(), actionId, request); + + BillAction updatedBillAction = billActionRepository.findById(savedBillAction.getId()).get(); + List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(updatedBillAction); + + assertThat(billActionDetails).hasSize(4) + .extracting("memberName", "price") + .containsExactlyInAnyOrder( + tuple("감자", 5000L), + tuple("고구마", 5000L), + tuple("당근", 5000L), + tuple("양파", 5000L) + ); + } + + @DisplayName("지출 내역을 삭제한다.") + @Test + void deleteBillAction() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + BillAction billAction = new BillAction(new Action(event, 1L), "커피", 50_900L); + billActionRepository.save(billAction); + Long actionId = billAction.getAction().getId(); + + billActionService.deleteBillAction(event.getToken(), actionId); + + assertThat(billActionRepository.findById(billAction.getId())).isEmpty(); + } + + @DisplayName("지출 내역을 삭제하면 지출 상세도 삭제된다.") + @Test + void deleteBillActionTest1() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "백호", MemberActionStatus.IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "망쵸", MemberActionStatus.IN, 2L); + BillAction billAction = new BillAction(new Action(event, 3L), "커피", 50_900L); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "백호", 25_450L, false); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "망쵸", 25_450L, false); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); + billActionRepository.save(billAction); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); + Long actionId = billAction.getAction().getId(); + + billActionService.deleteBillAction(event.getToken(), actionId); + + assertThat(billActionDetailRepository.findAll()).isEmpty(); + } + + @DisplayName("지출 내역 삭제 시 행사가 존재하지 않으면 예외가 발생한다.") + @Test + void deleteBillAction1() { + assertThatThrownBy(() -> billActionService.deleteBillAction("소하망쵸", 1L)) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/application/EventServiceTest.java b/server/src/test/java/server/haengdong/application/EventServiceTest.java new file mode 100644 index 000000000..407fa1457 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/EventServiceTest.java @@ -0,0 +1,231 @@ +package server.haengdong.application; + + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; +import static org.mockito.BDDMockito.given; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.request.MemberNameUpdateAppRequest; +import server.haengdong.application.request.MemberNamesUpdateAppRequest; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.EventAppResponse; +import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.application.response.MembersAppResponse; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.domain.event.EventTokenProvider; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class EventServiceTest extends ServiceTestSupport { + + @Autowired + private EventService eventService; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillActionRepository billActionRepository; + + @Autowired + private MemberActionRepository memberActionRepository; + + @MockBean + private EventTokenProvider eventTokenProvider; + + @DisplayName("행사를 생성한다") + @Test + void saveEventTest() { + EventAppRequest request = new EventAppRequest("test", "1234"); + given(eventTokenProvider.createToken()).willReturn("TOKEN"); + + EventAppResponse response = eventService.saveEvent(request); + + assertThat(response.token()).isEqualTo("TOKEN"); + } + + @DisplayName("토큰으로 행사를 조회한다.") + @Test + void findEventTest() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + + EventDetailAppResponse eventDetailAppResponse = eventService.findEvent(event.getToken()); + + assertThat(eventDetailAppResponse.eventName()).isEqualTo(event.getName()); + } + + @DisplayName("행사에 속한 모든 액션을 조회한다.") + @Test + void findActionsTest() { + Event event = Fixture.EVENT1; + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "토다리", IN, 1L); + Action action1 = new Action(event, 2L); + MemberAction memberAction1 = new MemberAction(action1, "쿠키", IN, 1L); + Action action2 = new Action(event, 3L); + BillAction billAction = new BillAction(action2, "뽕나무쟁이족발", 30000L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of(memberAction, memberAction1)); + billActionRepository.save(billAction); + + List<ActionAppResponse> actionAppResponses = eventService.findActions(event.getToken()); + + assertThat(actionAppResponses).hasSize(3) + .extracting(ActionAppResponse::actionId, + ActionAppResponse::name, + ActionAppResponse::price, + ActionAppResponse::sequence, + ActionAppResponse::actionTypeName) + .containsExactly( + tuple(1L, "토다리", null, 1L, "IN"), + tuple(2L, "쿠키", null, 2L, "IN"), + tuple(3L, "뽕나무쟁이족발", 30000L, 3L, "BILL") + ); + } + + @DisplayName("행사에 참여한 전체 인원을 중복 없이 조회한다.") + @Test + void findAllMembersTest() { + Event event = Fixture.EVENT1; + Action action1 = new Action(event, 1L); + Action action2 = new Action(event, 2L); + Action action3 = new Action(event, 3L); + Action action4 = new Action(event, 4L); + BillAction billAction = new BillAction(action3, "뽕나무쟁이족발", 30000L); + MemberAction memberAction1 = new MemberAction(action1, "토다리", IN, 1L); + MemberAction memberAction2 = new MemberAction(action2, "쿠키", IN, 1L); + MemberAction memberAction3 = new MemberAction(action4, "쿠키", OUT, 1L); + eventRepository.save(event); + billActionRepository.save(billAction); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); + + MembersAppResponse membersAppResponse = eventService.findAllMembers(event.getToken()); + + assertThat(membersAppResponse.memberNames()).containsExactlyInAnyOrder("토다리", "쿠키"); + } + + @DisplayName("행사 참여 인원들의 이름을 변경한다.") + @Test + void updateMember() { + Event event = Fixture.EVENT1; + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "토다리", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "쿠키", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "웨디", IN, 2L); + MemberAction memberAction4 = new MemberAction(new Action(event, 4L), "쿠키", OUT, 3L); + MemberAction memberAction5 = new MemberAction(new Action(event, 5L), "쿠키", IN, 4L); + MemberAction memberAction6 = new MemberAction(new Action(event, 6L), "쿠키", OUT, 5L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of( + memberAction1, memberAction2, memberAction3, memberAction4, memberAction5, memberAction6 + )); + + eventService.updateMember(event.getToken(), new MemberNamesUpdateAppRequest(List.of( + new MemberNameUpdateAppRequest("쿠키", "쿡쿡"), + new MemberNameUpdateAppRequest("토다리", "토쟁이") + ))); + + List<MemberAction> foundMemberActions = memberActionRepository.findAllByEvent(event); + assertThat(foundMemberActions) + .extracting(MemberAction::getId, MemberAction::getMemberName) + .contains( + tuple(memberAction1.getId(), "토쟁이"), + tuple(memberAction2.getId(), "쿡쿡"), + tuple(memberAction3.getId(), "웨디"), + tuple(memberAction4.getId(), "쿡쿡"), + tuple(memberAction5.getId(), "쿡쿡"), + tuple(memberAction6.getId(), "쿡쿡") + ); + } + + @DisplayName("이미 존재하는 인원의 이름으로 변경할 수 없다.") + @Test + void updateMember1() { + Event event = Fixture.EVENT1; + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "토다리", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "쿠키", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "웨디", IN, 2L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); + + MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( + new MemberNameUpdateAppRequest("쿠키", "쿡쿡"), + new MemberNameUpdateAppRequest("웨디", "토다리") + )); + + assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("존재하지 않는 인원은 변경할 수 없다.") + @Test + void updateMember2() { + Event event = Fixture.EVENT1; + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "토다리", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "쿠키", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "웨디", IN, 2L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); + + MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( + new MemberNameUpdateAppRequest("쿡쿡", "토쟁이"), + new MemberNameUpdateAppRequest("웨디", "말복") + )); + + assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("변경 전 참여 인원 이름이 중복될 수 없다.") + @Test + void updateMember3() { + Event event = Fixture.EVENT1; + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "토다리", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "쿠키", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "웨디", IN, 2L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); + + MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( + new MemberNameUpdateAppRequest("쿠키", "쿡쿡"), + new MemberNameUpdateAppRequest("쿠키", "토쟁이") + )); + + assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("변경 후 참여 인원 이름이 중복될 수 없다.") + @Test + void updateMember4() { + Event event = Fixture.EVENT1; + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "토다리", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "쿠키", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "웨디", IN, 2L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); + + MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( + new MemberNameUpdateAppRequest("쿠키", "쿡쿡"), + new MemberNameUpdateAppRequest("토다리", "쿡쿡") + )); + + assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java new file mode 100644 index 000000000..c04f06026 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java @@ -0,0 +1,223 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.CurrentMembers; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.action.MemberActionStatus; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class MemberActionFactoryTest extends ServiceTestSupport { + + @Autowired + private MemberActionFactory memberActionFactory; + + @Autowired + private MemberActionRepository memberActionRepository; + + @Autowired + private EventRepository eventRepository; + + @DisplayName("이전 멤버 액션이 시퀀스 기준으로 정렬되지 않은 상태에서 새로운 멤버 액션 요청을 검증한다.") + @Test + void createMemberActionsTest() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action1 = new Action(event, 1L); + Action action2 = new Action(event, 2L); + MemberAction memberAction1 = new MemberAction(action1, "토다리", MemberActionStatus.IN, 1L); + MemberAction memberAction2 = new MemberAction(action2, "토다리", MemberActionStatus.OUT, 2L); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); + + List<MemberAction> unorderedMemberActions = List.of(memberAction2, memberAction1); + CurrentMembers currentMembers = CurrentMembers.of(unorderedMemberActions); + Action startAction = new Action(event, 3L); + + assertThatThrownBy(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("인원 변동 액션을 생성한다.") + @Test + void createMemberActionsTest1() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest memberActionsSaveAppRequest = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); + Action startAction = new Action(event, 2L); + + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); + List<MemberAction> memberActions = memberActionFactory.createMemberActions(memberActionsSaveAppRequest, + currentMembers, startAction + ); + + assertThat(memberActions).hasSize(1) + .extracting(MemberAction::getAction, MemberAction::getMemberName, MemberAction::getStatus) + .containsExactly( + tuple(startAction, "토다리", MemberActionStatus.OUT) + ); + } + + @DisplayName("현재 행사에 참여 중인 경우에 퇴장할 수 있다.") + @Test + void createMemberActionsTest2() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); + Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에서 퇴장한 경우에 입장할 수 있다.") + @Test + void createMemberActionsTest3() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action1 = new Action(event, 1L); + MemberAction memberAction1 = new MemberAction(action1, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction1); + Action action2 = new Action(event, 2L); + MemberAction memberAction2 = new MemberAction(action2, "토다리", MemberActionStatus.OUT, 2L); + memberActionRepository.save(memberAction2); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "IN"))); + Action startAction = new Action(event, 3L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction1, memberAction2)); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에 입장한 적 없는 경우에 입장할 수 있다.") + @Test + void createMemberActionsTest4() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); + Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다.") + @Test + void createMemberActionTest5() { + Event event = eventRepository.save(Fixture.EVENT1); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "OUT"))); + Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of()); + + assertThatCode( + () -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("행사에 이미 참여 중인 경우 다시 입장할 수 없다.") + @Test + void createMemberActionTest6() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); + Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("한 명의 사용자는 동시에 여러 번 입장할 수 없다.") + @Test + void createMemberActionTest7() { + Event event = eventRepository.save(Fixture.EVENT1); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of( + new MemberActionSaveAppRequest("쿠키", "IN"), + new MemberActionSaveAppRequest("쿠키", "IN") + )); + Action startAction = new Action(event, 1L); + CurrentMembers currentMembers = CurrentMembers.of(List.of()); + + assertThatCode( + () -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("한 명의 사용자는 동시에 여러 번 퇴장할 수 없다.") + @Test + void createMemberActionTest8() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of( + new MemberActionSaveAppRequest("쿠키", "OUT"), + new MemberActionSaveAppRequest("쿠키", "OUT") + )); + Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("한 명의 사용자는 입장과 퇴장을 동시에 할 수 없다.") + @Test + void createMemberActionTest9() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of( + new MemberActionSaveAppRequest("쿠키", "IN"), + new MemberActionSaveAppRequest("쿠키", "OUT") + )); + Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java new file mode 100644 index 000000000..b6d29444c --- /dev/null +++ b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java @@ -0,0 +1,251 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.groups.Tuple.tuple; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; +import server.haengdong.domain.action.BillActionDetailRepository; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.action.MemberActionStatus; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class MemberActionServiceTest extends ServiceTestSupport { + + @Autowired + private MemberActionService memberActionService; + + @Autowired + private MemberActionRepository memberActionRepository; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillActionRepository billActionRepository; + + @Autowired + private BillActionDetailRepository billActionDetailRepository; + + @DisplayName("현재 행사에 참여하고 있는 경우에 나갈 수 있다.") + @Test + void saveMemberActionTest() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "망쵸", IN, 1L); + memberActionRepository.save(memberAction); + + assertThatCode(() -> memberActionService.saveMemberAction(event.getToken(), new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("망쵸", "OUT"))))) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에서 퇴장한 경우에 입장할 수 있다.") + @Test + void saveMemberActionTest1() { + Event event = eventRepository.save(Fixture.EVENT1); + Action actionOne = new Action(event, 1L); + MemberAction memberActionOne = new MemberAction(actionOne, "망쵸", IN, 1L); + memberActionRepository.save(memberActionOne); + + Action actionTwo = new Action(event, 2L); + MemberAction memberActionTwo = new MemberAction(actionTwo, "망쵸", OUT, 1L); + memberActionRepository.save(memberActionTwo); + + assertThatCode(() -> memberActionService.saveMemberAction(event.getToken(), new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("망쵸", "IN"))))) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다.") + @Test + void saveMemberActionTest2() { + MemberActionsSaveAppRequest appRequest = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("TOKEN", "OUT"))); + + assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", appRequest)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("이벤트가 없으면 현재 참여 인원을 조회할 수 없다.") + @Test + void getCurrentMembers() { + assertThatThrownBy(() -> memberActionService.getCurrentMembers("token")) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("행사의 전체 참여자 중에서 특정 참여자의 맴버 액션을 전부 삭제한다.") + @Test + void deleteMember() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "참여자", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "토다리", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "쿠키", IN, 1L); + MemberAction memberAction4 = new MemberAction(new Action(event, 4L), "소하", IN, 1L); + MemberAction memberAction5 = new MemberAction(new Action(event, 5L), "웨디", IN, 1L); + MemberAction memberAction6 = new MemberAction(new Action(event, 6L), "참여자", OUT, 1L); + memberActionRepository.saveAll( + List.of(memberAction1, memberAction2, memberAction3, memberAction4, memberAction5, memberAction6)); + + Event event2 = Fixture.EVENT2; + eventRepository.save(event2); + Action action2 = Action.createFirst(event2); + MemberAction anotherMemberAction = new MemberAction(action2, "참여자", IN, 1L); + memberActionRepository.save(anotherMemberAction); + + memberActionService.deleteMember(event.getToken(), "참여자"); + + List<MemberAction> memberActions = memberActionRepository.findAll(); + + assertThat(memberActions).hasSize(5) + .extracting("memberName", "status") + .containsExactly( + tuple("토다리", IN), + tuple("쿠키", IN), + tuple("소하", IN), + tuple("웨디", IN), + tuple("참여자", IN) + ); + } + + @DisplayName("이벤트에 속한 멤버을 삭제하면 전체 지출 내역 디테일이 초기화된다.") + @Test + void deleteMember1() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + MemberAction memberAction1 = createMemberAction(new Action(event, 1L), "토다리", IN, 1L); + Action targetAction = new Action(event, 2L); + MemberAction memberAction2 = createMemberAction(targetAction, "토다리", OUT, 2L); + MemberAction memberAction3 = createMemberAction(new Action(event, 3L), "쿠키", IN, 3L); + MemberAction memberAction4 = createMemberAction(new Action(event, 4L), "웨디", IN, 4L); + MemberAction memberAction5 = createMemberAction(new Action(event, 5L), "감자", IN, 5L); + memberActionRepository.saveAll( + List.of(memberAction1, + memberAction2, + memberAction3, + memberAction4, + memberAction5 + ) + ); + BillAction billAction = new BillAction(new Action(event, 6L), "뽕족", 100_000L); + billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "쿠키", 40_000L, true); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "웨디", 30_000L, false); + BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "감자", 30_000L, false); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3)); + List<BillActionDetail> allByBillAction = billActionDetailRepository.findAllByBillAction(billAction); + System.out.println("allByBillAction = " + allByBillAction.isEmpty()); + + memberActionService.deleteMember(event.getToken(), "쿠키"); + + List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(billAction); + + assertThat(billActionDetails).hasSize(2) + .extracting("memberName", "price") + .containsExactlyInAnyOrder( + tuple("웨디", 50_000L), + tuple("감자", 50_000L) + ); + } + + @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") + @Test + void deleteMemberAction() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + MemberAction memberAction1 = createMemberAction(new Action(event, 1L), "토다리", IN, 1L); + Action targetAction = new Action(event, 2L); + MemberAction memberAction2 = createMemberAction(targetAction, "토다리", OUT, 2L); + MemberAction memberAction3 = createMemberAction(new Action(event, 3L), "쿠키", IN, 3L); + MemberAction memberAction4 = createMemberAction(new Action(event, 4L), "웨디", IN, 4L); + MemberAction memberAction5 = createMemberAction(new Action(event, 5L), "토다리", IN, 5L); + MemberAction memberAction6 = createMemberAction(new Action(event, 6L), "토다리", OUT, 6L); + MemberAction memberAction7 = createMemberAction(new Action(event, 7L), "쿠키", OUT, 7L); + memberActionRepository.saveAll( + List.of(memberAction1, + memberAction2, + memberAction3, + memberAction4, + memberAction5, + memberAction6, + memberAction7) + ); + + memberActionService.deleteMemberAction(event.getToken(), targetAction.getId()); + List<MemberAction> memberActions = memberActionRepository.findAll(); + + assertThat(memberActions).hasSize(4) + .extracting("id", "memberName", "status") + .containsExactly( + tuple(memberAction1.getId(), "토다리", IN), + tuple(memberAction3.getId(), "쿠키", IN), + tuple(memberAction4.getId(), "웨디", IN), + tuple(memberAction7.getId(), "쿠키", OUT) + ); + } + + @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후 지출 내역 디테일이 초기화된다.") + @Test + void deleteMemberAction1() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + MemberAction memberAction1 = createMemberAction(new Action(event, 1L), "토다리", IN, 1L); + Action targetAction = new Action(event, 2L); + MemberAction memberAction2 = createMemberAction(targetAction, "토다리", OUT, 2L); + MemberAction memberAction3 = createMemberAction(new Action(event, 3L), "쿠키", IN, 3L); + MemberAction memberAction4 = createMemberAction(new Action(event, 4L), "웨디", IN, 4L); + MemberAction memberAction5 = createMemberAction(new Action(event, 5L), "감자", IN, 5L); + memberActionRepository.saveAll( + List.of(memberAction1, + memberAction2, + memberAction3, + memberAction4, + memberAction5 + ) + ); + BillAction billAction = new BillAction(new Action(event, 6L), "뽕족", 100_000L); + billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "쿠키", 40_000L, true); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "웨디", 30_000L, false); + BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "감자", 30_000L, false); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3)); + + memberActionService.deleteMemberAction(event.getToken(), targetAction.getId()); + List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(billAction); + + assertThat(billActionDetails).hasSize(4) + .extracting("memberName", "price") + .containsExactlyInAnyOrder( + tuple("토다리", 25_000L), + tuple("쿠키", 25_000L), + tuple("웨디", 25_000L), + tuple("감자", 25_000L) + ); + } + + private MemberAction createMemberAction( + Action action, + String memberName, + MemberActionStatus memberActionStatus, + long memberGroupId + ) { + return new MemberAction(action, memberName, memberActionStatus, memberGroupId); + } +} diff --git a/server/src/test/java/server/haengdong/application/ServiceTestSupport.java b/server/src/test/java/server/haengdong/application/ServiceTestSupport.java new file mode 100644 index 000000000..b0e2db0a6 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/ServiceTestSupport.java @@ -0,0 +1,11 @@ +package server.haengdong.application; + +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import server.haengdong.support.extension.DatabaseCleanerExtension; + +@ExtendWith(DatabaseCleanerExtension.class) +@SpringBootTest(webEnvironment= WebEnvironment.NONE) +abstract class ServiceTestSupport { +} diff --git a/server/src/test/java/server/haengdong/docs/ActionControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/ActionControllerDocsTest.java new file mode 100644 index 000000000..39c2d0bb8 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/ActionControllerDocsTest.java @@ -0,0 +1,70 @@ +package server.haengdong.docs; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import server.haengdong.application.ActionService; +import server.haengdong.application.response.MemberBillReportAppResponse; +import server.haengdong.presentation.ActionController; + +class ActionControllerDocsTest extends RestDocsSupport { + + private final ActionService actionService = mock(ActionService.class); + + @Override + protected Object initController() { + return new ActionController(actionService); + } + + @DisplayName("참여자별 정산 현황을 조회한다.") + @Test + void getMemberBillReports() throws Exception { + List<MemberBillReportAppResponse> memberBillReportAppResponses = List.of( + new MemberBillReportAppResponse("소하", 20_000L), new MemberBillReportAppResponse("토다리", 200_000L)); + + given(actionService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/actions/reports", "망쵸토큰") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].name").value(equalTo("소하"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].price").value(equalTo(20_000))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].name").value(equalTo("토다리"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].price").value(equalTo(200_000))) + .andDo( + document("getMemberBillReports", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("reports").type(JsonFieldType.ARRAY).description("전체 정산 현황 목록"), + fieldWithPath("reports[0].name").type(JsonFieldType.STRING) + .description("참여자 이름"), + fieldWithPath("reports[0].price").type(JsonFieldType.NUMBER) + .description("참여자 정산 금액") + )) + ); + } +} diff --git a/server/src/test/java/server/haengdong/docs/BillActionControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/BillActionControllerDocsTest.java new file mode 100644 index 000000000..7ed6fe6c4 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/BillActionControllerDocsTest.java @@ -0,0 +1,128 @@ +package server.haengdong.docs; + +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; +import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import server.haengdong.application.BillActionService; +import server.haengdong.presentation.BillActionController; +import server.haengdong.presentation.request.BillActionSaveRequest; +import server.haengdong.presentation.request.BillActionUpdateRequest; +import server.haengdong.presentation.request.BillActionsSaveRequest; + +class BillActionControllerDocsTest extends RestDocsSupport { + + private final BillActionService billActionService = mock(BillActionService.class); + + @Override + protected Object initController() { + return new BillActionController(billActionService); + } + + @DisplayName("지출 내역을 생성한다.") + @Test + void saveAllBillAction() throws Exception { + BillActionsSaveRequest request = new BillActionsSaveRequest( + List.of( + new BillActionSaveRequest("뽕족", 10_000L), + new BillActionSaveRequest("인생맥주", 10_000L) + ) + ); + String requestBody = objectMapper.writeValueAsString(request); + String eventId = "쿠키토큰"; + + mockMvc.perform(post("/api/events/{eventId}/bill-actions", eventId) + .contentType(MediaType.APPLICATION_JSON) + .cookie(EVENT_COOKIE) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo(document("createBillActions", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), + requestFields( + fieldWithPath("actions").description("생성할 지출 액션 목록"), + fieldWithPath("actions[0].title").description("생성할 지출 액션의 제목"), + fieldWithPath("actions[0].price").description("생성할 지출 액션의 금액") + ) + )); + } + + @DisplayName("지출 액션을 수정한다.") + @Test + void updateBillAction() throws Exception { + BillActionUpdateRequest request = new BillActionUpdateRequest("뽕족", 10_000L); + + String requestBody = objectMapper.writeValueAsString(request); + String eventId = "웨디토큰"; + + mockMvc.perform(put("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1L) + .cookie(EVENT_COOKIE) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo(document("updateBillAction", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("actionId").description("지출 액션 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), + requestFields( + fieldWithPath("title").description("수정할 지출 액션의 제목"), + fieldWithPath("price").description("수정할 지출 액션의 금액") + ) + )); + } + + @DisplayName("지출 내역을 삭제한다.") + @Test + void deleteBillAction() throws Exception { + String eventId = "토다리토큰"; + + mockMvc.perform(delete("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1) + .cookie(EVENT_COOKIE) + ) + .andDo(print()) + .andExpect(status().isOk()) + .andDo(document("deleteBillAction", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("actionId").description("지출 액션 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ) + )); + } +} diff --git a/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java new file mode 100644 index 000000000..f492195f3 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java @@ -0,0 +1,127 @@ +package server.haengdong.docs; + +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; +import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.restdocs.payload.JsonFieldType; +import server.haengdong.application.BillActionDetailService; +import server.haengdong.application.response.BillActionDetailAppResponse; +import server.haengdong.application.response.BillActionDetailsAppResponse; +import server.haengdong.presentation.BillActionDetailController; +import server.haengdong.presentation.request.BillActionDetailUpdateRequest; +import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; + +public class BillActionDetailControllerDocsTest extends RestDocsSupport { + + private final BillActionDetailService billActionDetailService = mock(BillActionDetailService.class); + + @Override + protected Object initController() { + return new BillActionDetailController(billActionDetailService); + } + + @DisplayName("참여자별 지출 금액을 조회한다.") + @Test + void findBillActionDetailsTest() throws Exception { + BillActionDetailsAppResponse appResponse = new BillActionDetailsAppResponse( + List.of(new BillActionDetailAppResponse("토다리", 1000L, false))); + given(billActionDetailService.findBillActionDetails(anyString(), anyLong())) + .willReturn(appResponse); + + mockMvc.perform(get("/api/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").isArray()) + .andExpect(jsonPath("$.members[0].name").value("토다리")) + .andExpect(jsonPath("$.members[0].price").value(1000L)) + .andExpect(jsonPath("$.members[0].isFixed").value(false)) + .andDo( + document("findBillActionDetailsTest", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("actionId").description("액션 ID") + ), requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), responseFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("전체 정산 수정 요청 목록"), + fieldWithPath("members[0].name").type(JsonFieldType.STRING) + .description("참여자 이름"), + fieldWithPath("members[0].price").type(JsonFieldType.NUMBER) + .description("참여자 정산 금액"), + fieldWithPath("members[0].isFixed").type(JsonFieldType.BOOLEAN) + .description("참여자 정산 금액 수정 여부") + ) + ) + ); + } + + @DisplayName("참여자별 지출 금액을 수정한다.") + @Test + void updateBillActionDetailsTest() throws Exception { + List<BillActionDetailUpdateRequest> billActionDetailUpdateRequests = List.of( + new BillActionDetailUpdateRequest("소하", 10000L, true), + new BillActionDetailUpdateRequest("웨디", 20000L, true) + ); + BillActionDetailsUpdateRequest request = new BillActionDetailsUpdateRequest( + billActionDetailUpdateRequests); + + String json = objectMapper.writeValueAsString(request); + + mockMvc.perform(put("/api/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L) + .cookie(EVENT_COOKIE) + .contentType(MediaType.APPLICATION_JSON) + .content(json)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("updateBillActionDetailsTest", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("actionId").description("액션 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), + requestFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("전체 정산 수정 요청 목록"), + fieldWithPath("members[0].name").type(JsonFieldType.STRING) + .description("참여자 이름"), + fieldWithPath("members[0].price").type(JsonFieldType.NUMBER) + .description("참여자 정산 금액"), + fieldWithPath("members[0].isFixed").type(JsonFieldType.BOOLEAN) + .description("참여자 정산 금액 수정 여부") + ) + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java new file mode 100644 index 000000000..88de2a3a6 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java @@ -0,0 +1,381 @@ +package server.haengdong.docs; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; +import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; +import static org.springframework.restdocs.cookies.CookieDocumentation.responseCookies; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; + +import java.time.Duration; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.restdocs.payload.JsonFieldType; +import server.haengdong.application.AuthService; +import server.haengdong.application.EventService; +import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.ActionAppResponse.ActionType; +import server.haengdong.application.response.EventAppResponse; +import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.application.response.MembersAppResponse; +import server.haengdong.infrastructure.auth.CookieProperties; +import server.haengdong.presentation.EventController; +import server.haengdong.presentation.request.EventLoginRequest; +import server.haengdong.presentation.request.EventSaveRequest; +import server.haengdong.presentation.request.MemberNameUpdateRequest; +import server.haengdong.presentation.request.MemberNamesUpdateRequest; + +public class EventControllerDocsTest extends RestDocsSupport { + + private final EventService eventService = mock(EventService.class); + private final AuthService authService = mock(AuthService.class); + private final CookieProperties cookieProperties = new CookieProperties( + true, true, "domain", "path", "none", Duration.ofDays(7) + ); + + @Override + protected Object initController() { + return new EventController(eventService, authService, cookieProperties); + } + + @DisplayName("이벤트를 생성한다.") + @Test + void saveEvent() throws Exception { + EventSaveRequest eventSaveRequest = new EventSaveRequest("토다리", "0987"); + String requestBody = objectMapper.writeValueAsString(eventSaveRequest); + String eventId = "쿠키 토큰"; + EventAppResponse eventAppResponse = new EventAppResponse(eventId); + given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); + given(authService.createToken(eventId)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("eventToken"); + + mockMvc.perform(post("/api/events") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(jsonPath("$.eventId").value("쿠키 토큰")) + .andDo( + document("createEvent", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + requestFields( + fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름"), + fieldWithPath("password").type(JsonFieldType.STRING).description("행사 비밀 번호") + ), + responseFields( + fieldWithPath("eventId").type(JsonFieldType.STRING) + .description("행사 ID") + ), + responseCookies( + cookieWithName("eventToken").description("행사 관리자용 토큰") + ) + ) + ); + } + + @DisplayName("토큰으로 행사를 조회한다.") + @Test + void findEventTest() throws Exception { + String eventId = "망쵸토큰"; + EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식"); + given(eventService.findEvent(eventId)).willReturn(eventDetailAppResponse); + + mockMvc.perform(get("/api/events/{eventId}", eventId)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.eventName").value("행동대장 회식")) + .andDo( + document("getEvent", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름") + ) + ) + ); + } + + @DisplayName("행사에 참여한 전체 인원을 중복 없이 조회한다.") + @Test + void findAllMembersTest() throws Exception { + MembersAppResponse memberAppResponse = new MembersAppResponse(List.of("토다리", "쿠키")); + given(eventService.findAllMembers(anyString())).willReturn(memberAppResponse); + + mockMvc.perform(get("/api/events/{eventId}/members", "TOKEN")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.memberNames").isArray()) + .andExpect(jsonPath("$.memberNames[0]").value("토다리")) + .andExpect(jsonPath("$.memberNames[1]").value("쿠키")) + .andDo( + document("findAllEventMember", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("memberNames").type(JsonFieldType.ARRAY) + .description("행사 참여자 목록") + ) + ) + ); + } + + @DisplayName("행사 참여 인원의 이름을 수정한다.") + @Test + void updateMember() throws Exception { + String token = "TOKEN"; + MemberNamesUpdateRequest memberNameUpdateRequest = new MemberNamesUpdateRequest(List.of( + new MemberNameUpdateRequest("토다링", "토쟁이"), + new MemberNameUpdateRequest("감자", "고구마") + )); + + String requestBody = objectMapper.writeValueAsString(memberNameUpdateRequest); + + mockMvc.perform(put("/api/events/{eventId}/members/nameChange", token) + .cookie(EVENT_COOKIE) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("updateEventMemberName", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), + requestFields( + fieldWithPath("members").type(JsonFieldType.ARRAY).description("수정할 참여자 목록"), + fieldWithPath("members[].before").type(JsonFieldType.STRING) + .description("수정 전 참여자 이름"), + fieldWithPath("members[].after").type(JsonFieldType.STRING) + .description("수정 후 참여자 이름") + ) + ) + ); + } + + @DisplayName("행사 어드민이 로그인한다.") + @Test + void loginEvent() throws Exception { + String token = "TOKEN"; + EventLoginRequest eventLoginRequest = new EventLoginRequest("1234"); + String requestBody = objectMapper.writeValueAsString(eventLoginRequest); + given(authService.createToken(token)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("eventToken"); + + mockMvc.perform(post("/api/events/{eventId}/login", token) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(status().isOk()) + .andDo( + document("eventLogin", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestFields( + fieldWithPath("password").type(JsonFieldType.STRING) + .description("행사 비밀 번호") + ), + responseCookies( + cookieWithName("eventToken").description("행사 관리자용 토큰") + ) + ) + ); + } + + @DisplayName("행사 전체 액션 이력 조회") + @Test + void findActions() throws Exception { + String token = "TOKEN"; + List<ActionAppResponse> actionAppResponses = List.of( + new ActionAppResponse(1L, "망쵸", null, 1L, ActionType.IN), + new ActionAppResponse(2L, "족발", 100L, 2L, ActionType.BILL), + new ActionAppResponse(3L, "인생네컷", 1000L, 3L, ActionType.BILL), + new ActionAppResponse(4L, "망쵸", null, 4L, ActionType.OUT) + ); + given(eventService.findActions(token)).willReturn(actionAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/actions", token) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.steps[0].type").value(equalTo("IN"))) + .andExpect(jsonPath("$.steps[0].stepName").value(equalTo("0차"))) + .andExpect(jsonPath("$.steps[0].members[0]").value(equalTo("망쵸"))) + .andExpect(jsonPath("$.steps[0].actions[0].actionId").value(equalTo(1))) + .andExpect(jsonPath("$.steps[0].actions[0].name").value(equalTo("망쵸"))) + .andExpect(jsonPath("$.steps[0].actions[0].price").value(equalTo(null))) + .andExpect(jsonPath("$.steps[0].actions[0].sequence").value(equalTo(1))) + + .andExpect(jsonPath("$.steps[1].type").value(equalTo("BILL"))) + .andExpect(jsonPath("$.steps[1].stepName").value(equalTo("1차"))) + .andExpect(jsonPath("$.steps[1].members[0]").value(equalTo("망쵸"))) + .andExpect(jsonPath("$.steps[1].actions[0].actionId").value(equalTo(2))) + .andExpect(jsonPath("$.steps[1].actions[0].name").value(equalTo("족발"))) + .andExpect(jsonPath("$.steps[1].actions[0].price").value(equalTo(100))) + .andExpect(jsonPath("$.steps[1].actions[0].sequence").value(equalTo(2))) + + .andExpect(jsonPath("$.steps[1].actions[1].actionId").value(equalTo(3))) + .andExpect(jsonPath("$.steps[1].actions[1].name").value(equalTo("인생네컷"))) + .andExpect(jsonPath("$.steps[1].actions[1].price").value(equalTo(1000))) + .andExpect(jsonPath("$.steps[1].actions[1].sequence").value(equalTo(3))) + + .andExpect(jsonPath("$.steps[2].type").value(equalTo("OUT"))) + .andExpect(jsonPath("$.steps[2].stepName").value(equalTo("1차"))) + .andExpect(jsonPath("$.steps[2].actions[0].actionId").value(equalTo(4))) + .andExpect(jsonPath("$.steps[2].actions[0].name").value(equalTo("망쵸"))) + .andExpect(jsonPath("$.steps[2].actions[0].price").value(equalTo(null))) + .andExpect(jsonPath("$.steps[2].actions[0].sequence").value(equalTo(4))) + + .andDo( + document("findActions", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("steps[].stepName").type(JsonFieldType.STRING) + .description("스탭 이름"), + fieldWithPath("steps[].type").type(JsonFieldType.STRING) + .description("액션 유형 [BILL, IN, OUT]"), + fieldWithPath("steps[].members").type(JsonFieldType.ARRAY) + .description("해당 step에 참여한 참여자 목록"), + fieldWithPath("steps[].actions[].actionId").type(JsonFieldType.NUMBER) + .description("액션 ID"), + fieldWithPath("steps[].actions[].name").type(JsonFieldType.STRING) + .description("참여자 액션일 경우 참여자 이름, 지출 액션일 경우 지출 내역 이름"), + fieldWithPath("steps[].actions[].price").type(JsonFieldType.NUMBER).optional() + .description("참여자 액션일 경우 null, 지출 액션일 경우 지출 금액"), + fieldWithPath("steps[].actions[].sequence").type(JsonFieldType.NUMBER) + .description("액션 순서"), + fieldWithPath("steps[].actions[].isFixed").type(JsonFieldType.BOOLEAN) + .description("지출 내역의 멤버별 고정 지출 금액 생성 여부") + ) + ) + ); + } + + @DisplayName("행사 전체 액션 이력 조회 v2") + @Test + void findActions2() throws Exception { + String token = "TOKEN"; + List<ActionAppResponse> actionAppResponses = List.of( + new ActionAppResponse(1L, "망쵸", null, 1L, ActionType.IN), + new ActionAppResponse(2L, "족발", 100L, 2L, ActionType.BILL), + new ActionAppResponse(3L, "인생네컷", 1000L, 3L, ActionType.BILL), + new ActionAppResponse(4L, "망쵸", null, 4L, ActionType.OUT) + ); + given(eventService.findActions(token)).willReturn(actionAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/actions/v2", token) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.actions[0].actionId").value(equalTo(1))) + .andExpect(jsonPath("$.actions[0].name").value(equalTo("망쵸"))) + .andExpect(jsonPath("$.actions[0].price").value(equalTo(null))) + .andExpect(jsonPath("$.actions[0].sequence").value(equalTo(1))) + .andExpect(jsonPath("$.actions[0].type").value(equalTo("IN"))) + + .andExpect(jsonPath("$.actions[1].actionId").value(equalTo(2))) + .andExpect(jsonPath("$.actions[1].name").value(equalTo("족발"))) + .andExpect(jsonPath("$.actions[1].price").value(equalTo(100))) + .andExpect(jsonPath("$.actions[1].sequence").value(equalTo(2))) + .andExpect(jsonPath("$.actions[1].type").value(equalTo("BILL"))) + + .andExpect(jsonPath("$.actions[2].actionId").value(equalTo(3))) + .andExpect(jsonPath("$.actions[2].name").value(equalTo("인생네컷"))) + .andExpect(jsonPath("$.actions[2].price").value(equalTo(1000))) + .andExpect(jsonPath("$.actions[2].sequence").value(equalTo(3))) + .andExpect(jsonPath("$.actions[2].type").value(equalTo("BILL"))) + + .andExpect(jsonPath("$.actions[3].actionId").value(equalTo(4))) + .andExpect(jsonPath("$.actions[3].name").value(equalTo("망쵸"))) + .andExpect(jsonPath("$.actions[3].price").value(equalTo(null))) + .andExpect(jsonPath("$.actions[3].sequence").value(equalTo(4))) + .andExpect(jsonPath("$.actions[3].type").value(equalTo("OUT"))) + + .andDo( + document("findActions", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("actions[].actionId").type(JsonFieldType.NUMBER) + .description("액션 ID"), + fieldWithPath("actions[].name").type(JsonFieldType.STRING) + .description("참여자 액션일 경우 참여자 이름, 지출 액션일 경우 지출 내역 이름"), + fieldWithPath("actions[].price").type(JsonFieldType.NUMBER).optional() + .description("참여자 액션일 경우 null, 지출 액션일 경우 지출 금액"), + fieldWithPath("actions[].sequence").type(JsonFieldType.NUMBER) + .description("액션 순서"), + fieldWithPath("actions[].type").type(JsonFieldType.STRING) + .description("액션 타입") + ) + ) + ); + } + + @DisplayName("행사 어드민 권한을 확인한다.") + @Test + void authenticateTest() throws Exception { + String token = "TOKEN"; + mockMvc.perform(post("/api/events/{eventId}/auth", token) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + + .andDo( + document("authenticateEvent", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰").optional() + ) + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java new file mode 100644 index 000000000..afd766c8f --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java @@ -0,0 +1,157 @@ +package server.haengdong.docs; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; +import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.restdocs.payload.JsonFieldType; +import server.haengdong.application.MemberActionService; +import server.haengdong.application.response.CurrentMemberAppResponse; +import server.haengdong.presentation.MemberActionController; +import server.haengdong.presentation.request.MemberActionsSaveRequest; + +public class MemberActionControllerDocsTest extends RestDocsSupport { + + private final MemberActionService memberActionService = mock(MemberActionService.class); + + @Override + protected Object initController() { + return new MemberActionController(memberActionService); + } + + @DisplayName("참여자 행동을 추가한다.") + @Test + void saveMemberActionTest() throws Exception { + MemberActionsSaveRequest memberActionsSaveRequest = new MemberActionsSaveRequest( + List.of("웨디", "소하", "토다리", "쿠키"), "IN"); + + String requestBody = objectMapper.writeValueAsString(memberActionsSaveRequest); + + mockMvc.perform(post("/api/events/{eventId}/member-actions", "망쵸토큰") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("createMemberAction", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("토큰 토큰") + ), + requestFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("액션 대상 참여자 목록"), + fieldWithPath("status").type(JsonFieldType.STRING) + .description("참여자 액션 상태 [IN(늦참), OUT(탈주)]") + ) + ) + ); + } + + @DisplayName("현재 참여 인원을 조회합니다.") + @Test + void getCurrentMembers() throws Exception { + List<CurrentMemberAppResponse> currentMemberAppResponses = List.of( + new CurrentMemberAppResponse("소하"), new CurrentMemberAppResponse("토다리")); + + given(memberActionService.getCurrentMembers(any())).willReturn(currentMemberAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/members/current", "망쵸토큰") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.memberNames[0]").value(equalTo("소하"))) + .andExpect(jsonPath("$.memberNames[1]").value(equalTo("토다리"))) + .andDo( + document("getCurrentMembers", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("memberNames").type(JsonFieldType.ARRAY) + .description("현재 탈주 가능한 참여 인원 이름 목록") + ) + ) + ); + } + + @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") + @Test + void deleteMemberAction() throws Exception { + String eventId = "망쵸토큰"; + Long actionId = 2L; + + mockMvc.perform(delete("/api/events/{eventId}/member-actions/{actionId}", eventId, actionId) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("deleteMemberAction", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("actionId").description("액션 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자용 토큰") + ) + ) + ); + } + + @DisplayName("행사의 전체 참여자 중에서 특정 참여자의 맴버 액션을 전부 삭제한다.") + @Test + void deleteMember() throws Exception { + String eventId = "망쵸토큰"; + String memberName = "행동대장"; + + mockMvc.perform(delete("/api/events/{eventId}/members/{memberName}", eventId, memberName) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("deleteAllMemberActionByName", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("memberName").description("행사 참여자 이름") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자용 토큰") + ) + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/docs/RestDocsSupport.java b/server/src/test/java/server/haengdong/docs/RestDocsSupport.java new file mode 100644 index 000000000..3e6901ba8 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/RestDocsSupport.java @@ -0,0 +1,28 @@ +package server.haengdong.docs; + +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.restdocs.RestDocumentationContextProvider; +import org.springframework.restdocs.RestDocumentationExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +@ExtendWith({RestDocumentationExtension.class}) +abstract class RestDocsSupport { + + protected MockMvc mockMvc; + + protected ObjectMapper objectMapper = new ObjectMapper(); + + @BeforeEach + void setUp(RestDocumentationContextProvider restDocumentation) { + this.mockMvc = MockMvcBuilders.standaloneSetup(initController()) + .apply(documentationConfiguration(restDocumentation)) + .build(); + } + + protected abstract Object initController(); +} diff --git a/server/src/test/java/server/haengdong/domain/action/ActionTest.java b/server/src/test/java/server/haengdong/domain/action/ActionTest.java new file mode 100644 index 000000000..6ff25479c --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/action/ActionTest.java @@ -0,0 +1,31 @@ +package server.haengdong.domain.action; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.domain.event.Event; +import server.haengdong.support.fixture.Fixture; + +class ActionTest { + + @DisplayName("액션의 초기 순서번호는 1이다.") + @Test + void createFirst() { + Event event = Fixture.EVENT1; + Action action = Action.createFirst(event); + + assertThat(action.getSequence()).isOne(); + } + + @DisplayName("현재 액션의 다음 액션의 순서는 1만큼 증가한다.") + @Test + void next() { + Event event = Fixture.EVENT1; + Action action = new Action(event, 2L); + + Action nextAction = action.next(); + + assertThat(nextAction.getSequence()).isEqualTo(3L); + } +} diff --git a/server/src/test/java/server/haengdong/domain/action/BillActionTest.java b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java new file mode 100644 index 000000000..ba1ab36f2 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java @@ -0,0 +1,89 @@ +package server.haengdong.domain.action; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static server.haengdong.support.fixture.Fixture.BILL_ACTION; +import static server.haengdong.support.fixture.Fixture.EVENT1; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import server.haengdong.domain.event.Event; +import server.haengdong.exception.HaengdongException; + +class BillActionTest { + + @DisplayName("지출 내역 제목의 앞뒤 공백을 제거한 길이가 1 ~ 30자가 아니면 지출을 생성할 수 없다.") + @ParameterizedTest + @ValueSource(strings = {"", " ", "1234567890123456789012345678901"}) + void validateTitle(String title) { + Event event = EVENT1; + Action action = new Action(event, 1L); + Long price = 100L; + + assertThatThrownBy(() -> new BillAction(action, title, price)) + .isInstanceOf(HaengdongException.class) + .hasMessage("앞뒤 공백을 제거한 지출 내역 제목은 1 ~ 30자여야 합니다."); + } + + @DisplayName("금액이 10,000,000 이하의 자연수가 아니면 지출을 생성할 수 없다.") + @ParameterizedTest + @ValueSource(longs = {0, 10_000_001, 20_000_000}) + void validatePrice(long price) { + Event event = EVENT1; + Action action = new Action(event, 1L); + String title = "title"; + + assertThatThrownBy(() -> new BillAction(action, title, price)) + .isInstanceOf(HaengdongException.class) + .hasMessage("지출 금액은 10,000,000 이하의 자연수여야 합니다."); + } + + @DisplayName("지출 내역을 올바르게 생성한다.") + @Test + void createBillAction() { + Event event = EVENT1; + Action action = new Action(event, 1L); + String title = "title"; + Long price = 1_000L; + + BillAction billAction = new BillAction(action, title, price); + + assertAll( + () -> assertThat(billAction.getAction()).isEqualTo(action), + () -> assertThat(billAction.getTitle()).isEqualTo(title), + () -> assertThat(billAction.getPrice()).isEqualTo(price) + ); + } + + @DisplayName("지출 액션에 멤버별 고정 금액이 설정되어 있는지 확인한다.") + @Test + void isFixed1() { + BillAction fixedBillAction = new BillAction(new Action(EVENT1, 1L), "인생네컷", 2_000L); + + List<BillActionDetail> unfixedBillActionDetails = List.of( + new BillActionDetail(BILL_ACTION, "감자", 1_000L, false), + new BillActionDetail(BILL_ACTION, "고구마", 1_000L, false) + ); + fixedBillAction.addDetails(unfixedBillActionDetails); + + assertThat(fixedBillAction.isFixed()).isEqualTo(false); + } + + @DisplayName("지출 액션에 멤버별 고정 금액이 설정되어 있는지 확인한다.") + @Test + void isFixed2() { + BillAction fixedBillAction = new BillAction(new Action(EVENT1, 1L), "인생네컷", 5_000L); + + List<BillActionDetail> unfixedBillActionDetails = List.of( + new BillActionDetail(BILL_ACTION, "감자", 4_000L, true), + new BillActionDetail(BILL_ACTION, "고구마", 1_000L, true) + ); + fixedBillAction.addDetails(unfixedBillActionDetails); + + assertThat(fixedBillAction.isFixed()).isEqualTo(true); + } +} diff --git a/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java b/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java new file mode 100644 index 000000000..93148abd3 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java @@ -0,0 +1,97 @@ +package server.haengdong.domain.action; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; + +import java.util.List; +import java.util.Set; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.domain.event.Event; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class CurrentMembersTest { + + @DisplayName("인원 변동 이력으로 현재 참여 인원을 계산한다.") + @Test + void of() { + Event event = Fixture.EVENT1; + List<MemberAction> memberActions = List.of( + new MemberAction(new Action(event, 1L), "망쵸", IN, 1L), + new MemberAction(new Action(event, 2L), "백호", IN, 1L), + new MemberAction(new Action(event, 3L), "백호", OUT, 1L), + new MemberAction(new Action(event, 4L), "웨디", IN, 1L) + ); + + CurrentMembers currentMembers = CurrentMembers.of(memberActions); + + assertThat(currentMembers.getMembers()) + .containsExactlyInAnyOrder("망쵸", "웨디"); + } + + @DisplayName("인원 변동 액션의 상태가 IN이면 현재 인원에 추가한다.") + @Test + void addMemberAction1() { + CurrentMembers currentMembers = new CurrentMembers(); + Event event = Fixture.EVENT1; + MemberAction memberAction = new MemberAction(new Action(event, 1L), "웨디", IN, 1L); + + CurrentMembers addedCurrentMembers = currentMembers.addMemberAction(memberAction); + Set<String> members = addedCurrentMembers.getMembers(); + + assertThat(members).hasSize(1) + .containsExactly("웨디"); + } + + @DisplayName("인원 변동 액션의 상태가 OUT이면 현재 인원에서 제외한다.") + @Test + void addMemberAction2() { + Event event = Fixture.EVENT1; + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "웨디", IN, 1L); + CurrentMembers currentMembers = new CurrentMembers().addMemberAction(memberAction1); + MemberAction memberAction2 = new MemberAction(new Action(event, 1L), "웨디", OUT, 1L); + + CurrentMembers addedCurrentMembers = currentMembers.addMemberAction(memberAction2); + + assertThat(addedCurrentMembers.getMembers()).hasSize(0); + } + + @DisplayName("현재 참여중인 인원은 나갈 수 있다.") + @Test + void validate1() { + CurrentMembers currentMembers = new CurrentMembers(Set.of("토다리")); + + assertThatCode(() -> currentMembers.validate("토다리", OUT)) + .doesNotThrowAnyException(); + } + + @DisplayName("현재 참여중이지 않은 인원은 들어올 수 있다.") + @Test + void validate2() { + CurrentMembers currentMembers = new CurrentMembers(Set.of("쿠키")); + + assertThatCode(() -> currentMembers.validate("토다리", IN)) + .doesNotThrowAnyException(); + } + + @DisplayName("현재 참여중인 인원은 들어올 수 없다.") + @Test + void validate3() { + CurrentMembers currentMembers = new CurrentMembers(Set.of("토다리")); + + assertThatCode(() -> currentMembers.validate("토다리", IN)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("현재 참여중이지 않은 인원은 나갈 수 없다.") + @Test + void validate4() { + CurrentMembers currentMembers = new CurrentMembers(Set.of("쿠키")); + + assertThatCode(() -> currentMembers.validate("토다리", OUT)) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java b/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java new file mode 100644 index 000000000..02070a537 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java @@ -0,0 +1,56 @@ +package server.haengdong.domain.action; + +import static org.assertj.core.api.Assertions.assertThat; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; +import static server.haengdong.support.fixture.Fixture.BILL_ACTION; + +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.domain.event.Event; +import server.haengdong.support.fixture.Fixture; + +class MemberBillReportTest { + + @DisplayName("액션 목록으로 참가자 정산 리포트를 생성한다.") + @Test + void createByActions() { + Event event = Fixture.EVENT1; + List<BillAction> billActions = List.of( + new BillAction(new Action(event, 4L), "뽕족", 60_000L), + new BillAction(new Action(event, 7L), "인생네컷", 20_000L) + ); + billActions.get(0).addDetails( + List.of( + new BillActionDetail(BILL_ACTION, "소하", 10_000L, false), + new BillActionDetail(BILL_ACTION, "감자", 40_000L, true), + new BillActionDetail(BILL_ACTION, "쿠키", 10_000L, false) + ) + ); + billActions.get(1).addDetails( + List.of( + new BillActionDetail(BILL_ACTION, "소하", 5_000L, true), + new BillActionDetail(BILL_ACTION, "쿠키", 15_000L, true) + ) + ); + List<MemberAction> memberActions = List.of( + new MemberAction(new Action(event, 1L), "소하", IN, 1L), + new MemberAction(new Action(event, 2L), "감자", IN, 1L), + new MemberAction(new Action(event, 3L), "쿠키", IN, 1L), + new MemberAction(new Action(event, 5L), "감자", OUT, 2L) + ); + + MemberBillReport memberBillReport = MemberBillReport.createByActions(billActions, memberActions); + + assertThat(memberBillReport.getReports()) + .containsAllEntriesOf( + Map.of( + "감자", 40_000L, + "쿠키", 25_000L, + "소하", 15_000L + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/domain/event/EventTest.java b/server/src/test/java/server/haengdong/domain/event/EventTest.java new file mode 100644 index 000000000..12c0c0569 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/event/EventTest.java @@ -0,0 +1,65 @@ +package server.haengdong.domain.event; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import server.haengdong.exception.HaengdongException; + +class EventTest { + + @DisplayName("공백 문자가 연속되지 않고, 이름이 2자 이상 20자 이하인 행사를 생성하면 예외가 발생하지 않는다.") + @ParameterizedTest + @ValueSource(strings = {"12", "12345678901234567890", "공 백", " 공백", "공백 ", " 공 백 "}) + void createSuccessTest(String eventName) { + assertThatCode(() -> new Event(eventName, "1234", "TEST_TOKEN")) + .doesNotThrowAnyException(); + } + + @DisplayName("공백 문자가 연속되면 예외가 발생한다.") + @ParameterizedTest + @ValueSource(strings = {" 공백", "공백 ", "공백 연속", "공 백"}) + void createFailTest1(String eventName) { + assertThatCode(() -> new Event(eventName, "1234", "TEST_TOKEN")) + .isInstanceOf(HaengdongException.class) + .hasMessage(String.format("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s", eventName)); + } + + @DisplayName("이름이 1자 미만이거나 20자 초과인 경우 예외가 발생한다.") + @ParameterizedTest + @ValueSource(strings = {"", " ", "123456789012345678901"}) + void createFilTest2(String eventName) { + assertThatCode(() -> new Event(eventName, "1234", "TEST_TOKEN")) + .isInstanceOf(HaengdongException.class) + .hasMessage(String.format("행사 이름은 1자 이상 20자 이하만 입력 가능합니다. 입력한 이름 길이 : %d", eventName.length())); + } + + @DisplayName("비밀번호는 4자리 숫자 입니다.") + @ParameterizedTest + @ValueSource(strings = {"1", "12", "123", "12345", "adgd"}) + void validatePassword(String password) { + assertThatCode(() -> new Event("이름", password, "TEST_TOKEN")) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("비밀번호가 다른지 검증한다.") + @Test + void isNotSamePassword() { + String rawPassword = "1234"; + Event event = new Event("이름", rawPassword, "TEST_TOKEN"); + + assertThat(event.isPasswordMismatch(rawPassword)).isFalse(); + } + + @DisplayName("비밀번호가 다른지 검증한다.") + @Test + void isNotSamePassword1() { + String rawPassword = "1234"; + Event event = new Event("이름", "5678", "TEST_TOKEN"); + + assertThat(event.isPasswordMismatch(rawPassword)).isTrue(); + } +} diff --git a/server/src/test/java/server/haengdong/domain/event/PasswordTest.java b/server/src/test/java/server/haengdong/domain/event/PasswordTest.java new file mode 100644 index 000000000..c504d3aa2 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/event/PasswordTest.java @@ -0,0 +1,19 @@ +package server.haengdong.domain.event; + +import static org.assertj.core.api.Assertions.assertThatCode; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import server.haengdong.exception.HaengdongException; + +class PasswordTest { + + @DisplayName("비밀번호는 4자리 숫자 입니다.") + @ParameterizedTest + @ValueSource(strings = {"1", "12", "123", "12345", "adgd"}) + void validatePassword(String rawPassword) { + assertThatCode(() -> new Password(rawPassword)) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java new file mode 100644 index 000000000..1de5889b5 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java @@ -0,0 +1,36 @@ +package server.haengdong.presentation; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import server.haengdong.application.response.MemberBillReportAppResponse; + +class ActionControllerTest extends ControllerTestSupport { + + @DisplayName("참여자별 정산 현황을 조회한다.") + @Test + void getMemberBillReports() throws Exception { + List<MemberBillReportAppResponse> memberBillReportAppResponses = List.of( + new MemberBillReportAppResponse("소하", 20_000L), new MemberBillReportAppResponse("토다리", 200_000L)); + + given(actionService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/actions/reports", "망쵸토큰") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].name").value(equalTo("소하"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].price").value(equalTo(20_000))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].name").value(equalTo("토다리"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].price").value(equalTo(200_000))); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java new file mode 100644 index 000000000..4420e369c --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java @@ -0,0 +1,97 @@ +package server.haengdong.presentation; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doThrow; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; +import server.haengdong.presentation.request.BillActionSaveRequest; +import server.haengdong.presentation.request.BillActionUpdateRequest; +import server.haengdong.presentation.request.BillActionsSaveRequest; + +class BillActionControllerTest extends ControllerTestSupport { + + @DisplayName("지출 내역을 생성한다.") + @Test + void saveAllBillAction() throws Exception { + BillActionsSaveRequest request = new BillActionsSaveRequest( + List.of( + new BillActionSaveRequest("뽕족", 10_000L), + new BillActionSaveRequest("인생맥주", 10_000L) + ) + ); + String requestBody = objectMapper.writeValueAsString(request); + String eventId = "쿠키토큰"; + + mockMvc.perform(post("/api/events/{eventId}/bill-actions", eventId) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("title이 비어 있는 경우 지출 내역을 생성할 수 없다.") + @Test + void saveAllBillAction1() throws Exception { + BillActionsSaveRequest request = new BillActionsSaveRequest( + List.of( + new BillActionSaveRequest("", 10_000L), + new BillActionSaveRequest("인생맥주", 10_000L) + ) + ); + String requestBody = objectMapper.writeValueAsString(request); + String eventId = "소하토큰"; + + mockMvc.perform(post("/api/events/{eventId}/bill-actions", eventId) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isBadRequest()); + } + + @DisplayName("지출 액션을 수정한다.") + @Test + void updateBillAction() throws Exception { + BillActionUpdateRequest request = new BillActionUpdateRequest("뽕족", 10_000L); + + String requestBody = objectMapper.writeValueAsString(request); + String eventId = "웨디토큰"; + + mockMvc.perform(put("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1L) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("지출 내역을 삭제한다.") + @Test + void deleteBillAction() throws Exception { + String eventId = "토다리토큰"; + + mockMvc.perform(delete("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("존재하지 않는 행사에 대한 지출 내역을 삭제할 수 없다.") + @Test + void deleteBillAction1() throws Exception { + String eventId = "이상해토큰"; + doThrow(new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)) + .when(billActionService).deleteBillAction(any(String.class), any(Long.class)); + + mockMvc.perform(delete("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1)) + .andDo(print()) + .andExpect(status().isBadRequest()); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java new file mode 100644 index 000000000..6b595ee27 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java @@ -0,0 +1,56 @@ +package server.haengdong.presentation; + +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import server.haengdong.application.response.BillActionDetailAppResponse; +import server.haengdong.application.response.BillActionDetailsAppResponse; +import server.haengdong.presentation.request.BillActionDetailUpdateRequest; +import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; + +class BillActionDetailControllerTest extends ControllerTestSupport { + + @DisplayName("참여자별 지출 금액을 조회한다.") + @Test + void findBillActionDetails() throws Exception { + BillActionDetailsAppResponse appResponse = new BillActionDetailsAppResponse( + List.of(new BillActionDetailAppResponse("토다리", 1000L, false))); + given(billActionDetailService.findBillActionDetails(anyString(), anyLong())) + .willReturn(appResponse); + + mockMvc.perform(get("/api/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").isArray()) + .andExpect(jsonPath("$.members[0].name").value("토다리")) + .andExpect(jsonPath("$.members[0].price").value(1000L)); + } + + @DisplayName("참여자별 지출 금액을 수정한다.") + @Test + void updateBillActionDetailsTest() throws Exception { + List<BillActionDetailUpdateRequest> billActionDetailUpdateRequests = List.of( + new BillActionDetailUpdateRequest("소하", 10000L, true), + new BillActionDetailUpdateRequest("웨디", 20000L, true) + ); + BillActionDetailsUpdateRequest request = new BillActionDetailsUpdateRequest( + billActionDetailUpdateRequests); + + String json = objectMapper.writeValueAsString(request); + + mockMvc.perform(put("/api/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L) + .contentType(MediaType.APPLICATION_JSON) + .content(json)) + .andDo(print()) + .andExpect(status().isOk()); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java b/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java new file mode 100644 index 000000000..46489b1a5 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java @@ -0,0 +1,53 @@ +package server.haengdong.presentation; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.FilterType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import server.haengdong.application.ActionService; +import server.haengdong.application.AuthService; +import server.haengdong.application.BillActionDetailService; +import server.haengdong.application.BillActionService; +import server.haengdong.application.EventService; +import server.haengdong.application.MemberActionService; + +@WebMvcTest( + controllers = { + EventController.class, + ActionController.class, + BillActionController.class, + MemberActionController.class, + BillActionDetailController.class + }, + excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {WebMvcConfigurer.class})} +) +abstract class ControllerTestSupport { + + @Autowired + protected MockMvc mockMvc; + + @Autowired + protected ObjectMapper objectMapper; + + @MockBean + protected EventService eventService; + + @MockBean + protected AuthService authService; + + @MockBean + protected ActionService actionService; + + @MockBean + protected MemberActionService memberActionService; + + @MockBean + protected BillActionService billActionService; + + @MockBean + protected BillActionDetailService billActionDetailService; +} diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java new file mode 100644 index 000000000..fcfe48d01 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java @@ -0,0 +1,111 @@ +package server.haengdong.presentation; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.response.EventAppResponse; +import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.application.response.MembersAppResponse; +import server.haengdong.presentation.request.EventLoginRequest; +import server.haengdong.presentation.request.EventSaveRequest; +import server.haengdong.presentation.request.MemberNameUpdateRequest; +import server.haengdong.presentation.request.MemberNamesUpdateRequest; + + +class EventControllerTest extends ControllerTestSupport { + + @DisplayName("이벤트를 생성한다.") + @Test + void saveEvent() throws Exception { + EventSaveRequest eventSaveRequest = new EventSaveRequest("토다리", "0987"); + String requestBody = objectMapper.writeValueAsString(eventSaveRequest); + String eventId = "망쵸토큰"; + EventAppResponse eventAppResponse = new EventAppResponse(eventId); + given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); + given(authService.createToken(eventId)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("eventToken"); + + mockMvc.perform(post("/api/events") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(jsonPath("$.eventId").value("망쵸토큰")); + } + + @DisplayName("토큰으로 행사를 조회한다.") + @Test + void findEventTest() throws Exception { + String eventId = "망쵸토큰"; + EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식"); + given(eventService.findEvent(eventId)).willReturn(eventDetailAppResponse); + + mockMvc.perform(get("/api/events/{eventId}", eventId)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.eventName").value("행동대장 회식")); + } + + @DisplayName("행사에 참여한 전체 인원을 중복 없이 조회한다.") + @Test + void findAllMembersTest() throws Exception { + MembersAppResponse memberAppResponse = new MembersAppResponse(List.of("토다리", "쿠키")); + given(eventService.findAllMembers(anyString())).willReturn(memberAppResponse); + + mockMvc.perform(get("/api/events/{eventId}/members", "TOKEN")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.memberNames").isArray()) + .andExpect(jsonPath("$.memberNames[0]").value("토다리")) + .andExpect(jsonPath("$.memberNames[1]").value("쿠키")); + } + + @DisplayName("행사 참여 인원의 이름을 수정한다.") + @Test + void updateMember() throws Exception { + String token = "TOKEN"; + MemberNamesUpdateRequest memberNameUpdateRequest = new MemberNamesUpdateRequest(List.of( + new MemberNameUpdateRequest("토다링", "토쟁이"), + new MemberNameUpdateRequest("감자", "고구마") + )); + + String requestBody = objectMapper.writeValueAsString(memberNameUpdateRequest); + + mockMvc.perform(put("/api/events/{eventId}/members/nameChange", token) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("행사 어드민이 로그인한다.") + @Test + void loginEvent() throws Exception { + String token = "TOKEN"; + EventLoginRequest eventLoginRequest = new EventLoginRequest("1234"); + String requestBody = objectMapper.writeValueAsString(eventLoginRequest); + given(authService.createToken(token)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("eventToken"); + + mockMvc.perform(post("/api/events/{eventId}/login", token) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(status().isOk()); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java new file mode 100644 index 000000000..f50c70a17 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java @@ -0,0 +1,74 @@ +package server.haengdong.presentation; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import server.haengdong.application.response.CurrentMemberAppResponse; +import server.haengdong.presentation.request.MemberActionsSaveRequest; + +class MemberActionControllerTest extends ControllerTestSupport { + + @DisplayName("참여자 행동을 추가한다.") + @Test + void saveMemberActionTest() throws Exception { + MemberActionsSaveRequest memberActionsSaveRequest = new MemberActionsSaveRequest( + List.of("웨디", "소하", "토다리", "쿠키"), "IN"); + + String requestBody = objectMapper.writeValueAsString(memberActionsSaveRequest); + + mockMvc.perform(post("/api/events/{eventId}/member-actions", "망쵸토큰") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("현재 참여 인원을 조회합니다.") + @Test + void getCurrentMembers() throws Exception { + List<CurrentMemberAppResponse> currentMemberAppResponses = List.of( + new CurrentMemberAppResponse("소하"), new CurrentMemberAppResponse("토다리")); + + given(memberActionService.getCurrentMembers(any())).willReturn(currentMemberAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/members/current", "망쵸토큰") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.memberNames[0]").value(equalTo("소하"))) + .andExpect(jsonPath("$.memberNames[1]").value(equalTo("토다리"))); + } + + @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") + @Test + void deleteMemberAction() throws Exception { + String eventId = "망쵸토큰"; + Long actionId = 2L; + + mockMvc.perform(delete("/api/events/{eventId}/member-actions/{actionId}", eventId, actionId)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("행사의 전체 참여자 중에서 특정 참여자의 맴버 액션을 전부 삭제한다.") + @Test + void deleteMember() throws Exception { + String eventId = "망쵸토큰"; + String memberName = "행동대장"; + + mockMvc.perform(delete("/api/events/{eventId}/members/{memberName}", eventId, memberName)) + .andDo(print()) + .andExpect(status().isOk()); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java b/server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java new file mode 100644 index 000000000..051fcae0f --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java @@ -0,0 +1,63 @@ +package server.haengdong.presentation.response; + + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.ActionAppResponse.ActionType; + +class StepsResponseTest { + + @DisplayName("이웃한 같은 타입의 액션들을 그룹화 하여 응답객체를 생성한다.") + @Test + void of() { + List<ActionAppResponse> actions = List.of( + new ActionAppResponse(1L, "망쵸", null, 1L, ActionType.IN), + new ActionAppResponse(2L, "백호", null, 2L, ActionType.IN), + new ActionAppResponse(3L, "감자탕", 10_000L, 3L, ActionType.BILL), + new ActionAppResponse(4L, "인생네컷", 10_000L, 4L, ActionType.BILL), + new ActionAppResponse(5L, "소하", null, 5L, ActionType.IN), + new ActionAppResponse(6L, "웨디", null, 6L, ActionType.IN), + new ActionAppResponse(7L, "망쵸", null, 7L, ActionType.OUT), + new ActionAppResponse(8L, "백호", null, 8L, ActionType.OUT), + new ActionAppResponse(9L, "노래방", 20_000L, 9L, ActionType.BILL) + ); + + StepsResponse stepsResponse = StepsResponse.of(actions); + + StepsResponse expected = new StepsResponse( + List.of( + new StepResponse("0차", "IN", List.of("망쵸", "백호"), List.of( + new ActionResponse(1L, "망쵸", null, 1L), + new ActionResponse(2L, "백호", null, 2L) + )), + new StepResponse("1차", "BILL", List.of("망쵸", "백호"), List.of( + new ActionResponse(3L, "감자탕", 10_000L, 3L), + new ActionResponse(4L, "인생네컷", 10_000L, 4L) + )), + new StepResponse("1차", "IN", List.of("망쵸", "백호", "소하", "웨디"), List.of( + new ActionResponse(5L, "소하", null, 5L), + new ActionResponse(6L, "웨디", null, 6L) + )), + new StepResponse("1차", "OUT", List.of("소하", "웨디"), List.of( + new ActionResponse(7L, "망쵸", null, 7L), + new ActionResponse(8L, "백호", null, 8L) + )), + new StepResponse("2차", "BILL", List.of("소하", "웨디"), List.of( + new ActionResponse(9L, "노래방", 20_000L, 9L) + )) + ) + ); + assertThat(stepsResponse).isEqualTo(expected); + } + + @DisplayName("액션이 없으면 빈 스탭들이 만들어진다.") + @Test + void ofEmpty() { + StepsResponse stepsResponse = StepsResponse.of(List.of()); + assertThat(stepsResponse.steps()).isEmpty(); + } +} diff --git a/server/src/test/java/server/haengdong/support/extension/DatabaseCleaner.java b/server/src/test/java/server/haengdong/support/extension/DatabaseCleaner.java new file mode 100644 index 000000000..346e81d2d --- /dev/null +++ b/server/src/test/java/server/haengdong/support/extension/DatabaseCleaner.java @@ -0,0 +1,52 @@ +package server.haengdong.support.extension; + +import jakarta.annotation.PostConstruct; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import java.util.List; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +class DatabaseCleaner { + + private static final String REFERENTIAL_FORMAT = "set referential_integrity %b;"; + private static final String TRUNCATE_FORMAT = "truncate table %s restart identity;"; + + @PersistenceContext + private EntityManager em; + private String truncateTablesQuery; + + @PostConstruct + public void createTruncateQuery() { + List<String> tableNames = getTableNames(); + StringBuilder stringBuilder = new StringBuilder(); + + for (String tableName : tableNames) { + String truncateQuery = String.format(TRUNCATE_FORMAT, tableName); + stringBuilder.append(truncateQuery); + } + truncateTablesQuery = stringBuilder.toString(); + } + + private List<String> getTableNames() { + String sql = """ + select table_name + from information_schema.tables + where table_schema = 'PUBLIC' + """; + return em.createNativeQuery(sql).getResultList(); + } + + @Transactional + public void clear() { + em.clear(); + truncate(); + } + + private void truncate() { + em.createNativeQuery(String.format(REFERENTIAL_FORMAT, false)).executeUpdate(); + em.createNativeQuery(truncateTablesQuery).executeUpdate(); + em.createNativeQuery(String.format(REFERENTIAL_FORMAT, true)).executeUpdate(); + } +} diff --git a/server/src/test/java/server/haengdong/support/extension/DatabaseCleanerExtension.java b/server/src/test/java/server/haengdong/support/extension/DatabaseCleanerExtension.java new file mode 100644 index 000000000..653ecadb3 --- /dev/null +++ b/server/src/test/java/server/haengdong/support/extension/DatabaseCleanerExtension.java @@ -0,0 +1,19 @@ +package server.haengdong.support.extension; + +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +public class DatabaseCleanerExtension implements AfterEachCallback { + + @Override + public void afterEach(ExtensionContext context) { + DatabaseCleaner databaseCleaner = getDataCleaner(context); + databaseCleaner.clear(); + } + + private DatabaseCleaner getDataCleaner(ExtensionContext extensionContext) { + return SpringExtension.getApplicationContext(extensionContext) + .getBean(DatabaseCleaner.class); + } +} diff --git a/server/src/test/java/server/haengdong/support/fixture/Fixture.java b/server/src/test/java/server/haengdong/support/fixture/Fixture.java new file mode 100644 index 000000000..6844915d9 --- /dev/null +++ b/server/src/test/java/server/haengdong/support/fixture/Fixture.java @@ -0,0 +1,15 @@ +package server.haengdong.support.fixture; + +import jakarta.servlet.http.Cookie; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.event.Event; + +public class Fixture { + + public static final Event EVENT1 = new Event("쿠키", "1234", "TOKEN1"); + public static final Event EVENT2 = new Event("웨디", "1234", "TOKEN2"); + public static final Cookie EVENT_COOKIE = new Cookie("eventToken", "토큰토큰"); + public static final Action ACTION = new Action(EVENT1, 1L); + public static final BillAction BILL_ACTION = new BillAction(ACTION, "뽕족", 30_000L); +} From 89a7a4784143b010bc425aa128e81882ea39a0ce Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Fri, 23 Aug 2024 00:48:35 +0900 Subject: [PATCH 164/178] =?UTF-8?q?fix:=20=EC=B0=B8=EC=97=AC=EC=9E=90=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD=EC=8B=9C=20=EC=A7=80?= =?UTF-8?q?=EC=B6=9C=20=EC=83=81=EC=84=B8=20=EC=9D=B4=EB=A6=84=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20=EC=95=88=EB=90=98=EB=8A=94=20=EB=B2=84=EA=B7=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#498)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/server/haengdong/application/EventService.java | 4 ++++ .../java/server/haengdong/domain/action/BillActionDetail.java | 4 ++++ .../haengdong/domain/action/BillActionDetailRepository.java | 2 ++ 3 files changed, 10 insertions(+) diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java index 834c0e10a..6b4cb755f 100644 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -16,6 +16,7 @@ import server.haengdong.application.response.EventDetailAppResponse; import server.haengdong.application.response.MembersAppResponse; import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetailRepository; import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionRepository; @@ -35,6 +36,7 @@ public class EventService { private final EventTokenProvider eventTokenProvider; private final BillActionRepository billActionRepository; private final MemberActionRepository memberActionRepository; + private final BillActionDetailRepository billActionDetailRepository; @Transactional public EventAppResponse saveEvent(EventAppRequest request) { @@ -149,6 +151,8 @@ private void validateAfterMemberNameNotExist(Event event, String afterName) { private void updateMemberName(Event event, String beforeName, String afterName) { memberActionRepository.findAllByAction_EventAndMemberName(event, beforeName) .forEach(memberAction -> memberAction.updateMemberName(afterName)); + billActionDetailRepository.findAllByMemberName(beforeName) + .forEach(billActionDetail -> billActionDetail.updateMemberName(afterName)); } public void validatePassword(EventLoginAppRequest request) throws HaengdongException { diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java index ad13e6ab2..ffdfe04a3 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java @@ -43,6 +43,10 @@ public void updateIsFixed(boolean isFixed) { this.isFixed = isFixed; } + public void updateMemberName(String name) { + this.memberName = name; + } + public boolean hasMemberName(String memberName) { return this.memberName.equals(memberName); } diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java index d1d7cfe0f..17a082657 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java @@ -14,4 +14,6 @@ public interface BillActionDetailRepository extends JpaRepository<BillActionDeta where bd.billAction = :billAction """) List<BillActionDetail> findAllByBillAction(BillAction billAction); + + List<BillActionDetail> findAllByMemberName(String memberName); } From 7e1f274aa7afcc5f74f30d8dc5da32a4dbd9a05f Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Fri, 23 Aug 2024 00:56:23 +0900 Subject: [PATCH 165/178] =?UTF-8?q?fix=20=ED=96=89=EC=82=AC=20=EC=9D=B8?= =?UTF-8?q?=EC=9B=90=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD=EC=8B=9C=20?= =?UTF-8?q?=EC=A7=80=EC=B6=9C=20=EC=83=81=EC=84=B8=EC=9D=98=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=EC=9D=B4=20=EB=B3=80=EA=B2=BD=EB=90=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EB=8A=94=20=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?(#500)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/server/haengdong/application/EventService.java | 5 +++++ .../server/haengdong/domain/action/BillActionDetail.java | 4 ++++ .../haengdong/domain/action/BillActionDetailRepository.java | 2 ++ 3 files changed, 11 insertions(+) diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java index 834c0e10a..d0628c0ef 100644 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -16,6 +16,7 @@ import server.haengdong.application.response.EventDetailAppResponse; import server.haengdong.application.response.MembersAppResponse; import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetailRepository; import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionRepository; @@ -35,6 +36,8 @@ public class EventService { private final EventTokenProvider eventTokenProvider; private final BillActionRepository billActionRepository; private final MemberActionRepository memberActionRepository; + private final BillActionDetailRepository billActionDetailRepository; + @Transactional public EventAppResponse saveEvent(EventAppRequest request) { @@ -149,6 +152,8 @@ private void validateAfterMemberNameNotExist(Event event, String afterName) { private void updateMemberName(Event event, String beforeName, String afterName) { memberActionRepository.findAllByAction_EventAndMemberName(event, beforeName) .forEach(memberAction -> memberAction.updateMemberName(afterName)); + billActionDetailRepository.findAllByMemberName(beforeName) + .forEach(billActionDetail -> billActionDetail.updateMemberName(afterName)); } public void validatePassword(EventLoginAppRequest request) throws HaengdongException { diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java index ad13e6ab2..ffdfe04a3 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java @@ -43,6 +43,10 @@ public void updateIsFixed(boolean isFixed) { this.isFixed = isFixed; } + public void updateMemberName(String name) { + this.memberName = name; + } + public boolean hasMemberName(String memberName) { return this.memberName.equals(memberName); } diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java index d1d7cfe0f..17a082657 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java @@ -14,4 +14,6 @@ public interface BillActionDetailRepository extends JpaRepository<BillActionDeta where bd.billAction = :billAction """) List<BillActionDetail> findAllByBillAction(BillAction billAction); + + List<BillActionDetail> findAllByMemberName(String memberName); } From 1c7f25dc572a6ace3440decc5b726a3d2bbc4d1b Mon Sep 17 00:00:00 2001 From: Arachneee <jhg2819@naver.com> Date: Fri, 23 Aug 2024 01:59:51 +0900 Subject: [PATCH 166/178] =?UTF-8?q?fix:=20=EC=B0=B8=EC=97=AC=EC=9E=90=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD=EC=8B=9C=20=EC=A7=80?= =?UTF-8?q?=EC=B6=9C=20=EC=83=81=EC=84=B8=20=EC=9D=B4=EB=A6=84=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20=EC=95=88=EB=90=98=EB=8A=94=20=EB=B2=84=EA=B7=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/server/haengdong/application/EventService.java | 2 +- .../haengdong/domain/action/BillActionDetailRepository.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java index d0628c0ef..1aaddd0f9 100644 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -152,7 +152,7 @@ private void validateAfterMemberNameNotExist(Event event, String afterName) { private void updateMemberName(Event event, String beforeName, String afterName) { memberActionRepository.findAllByAction_EventAndMemberName(event, beforeName) .forEach(memberAction -> memberAction.updateMemberName(afterName)); - billActionDetailRepository.findAllByMemberName(beforeName) + billActionDetailRepository.findAllByBillAction_Action_EventAndMemberName(event, beforeName) .forEach(billActionDetail -> billActionDetail.updateMemberName(afterName)); } diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java index 17a082657..05de55304 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java @@ -4,6 +4,7 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; +import server.haengdong.domain.event.Event; @Repository public interface BillActionDetailRepository extends JpaRepository<BillActionDetail, Long> { @@ -15,5 +16,5 @@ public interface BillActionDetailRepository extends JpaRepository<BillActionDeta """) List<BillActionDetail> findAllByBillAction(BillAction billAction); - List<BillActionDetail> findAllByMemberName(String memberName); + List<BillActionDetail> findAllByBillAction_Action_EventAndMemberName(Event event, String memberName); } From f75a7c978b79b2bf3b208643936ba5d3df710ed8 Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Thu, 5 Sep 2024 15:38:37 +0900 Subject: [PATCH 167/178] =?UTF-8?q?refactor:=20=EA=B4=80=EB=A6=AC=EC=9E=90?= =?UTF-8?q?=EC=9A=A9=20=ED=95=B8=EB=93=A4=EB=9F=AC=20=EB=A9=94=EC=86=8C?= =?UTF-8?q?=EB=93=9C=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81=20=EB=B0=8F=20?= =?UTF-8?q?Controller=20=EB=A9=94=EC=86=8C=EB=93=9C=20=EC=9C=84=EC=B9=98?= =?UTF-8?q?=20=EC=A1=B0=EC=A0=95=20(#540)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: juha <khabh@naver.com> Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <gosmdochee2@gmail.com> --- .../haengdong/config/AdminInterceptor.java | 8 +- .../server/haengdong/config/WebMvcConfig.java | 3 +- .../presentation/ActionController.java | 26 --- .../BillActionDetailController.java | 15 -- .../presentation/EventController.java | 47 ++-- .../presentation/MemberActionController.java | 34 --- .../AdminBillActionController.java} | 33 ++- .../admin/AdminEventController.java | 39 ++++ .../admin/AdminMemberActionController.java | 48 ++++ .../docs/ActionControllerDocsTest.java | 70 ------ ...=> AdminBillActionControllerDocsTest.java} | 60 ++++- .../docs/AdminEventControllerDocsTest.java | 99 ++++++++ .../AdminMemberActionControllerDocsTest.java | 121 ++++++++++ .../BillActionDetailControllerDocsTest.java | 48 ---- .../docs/EventControllerDocsTest.java | 215 ++++++++---------- .../docs/MemberActionControllerDocsTest.java | 91 -------- .../presentation/ActionControllerTest.java | 32 --- .../BillActionDetailControllerTest.java | 24 -- .../presentation/ControllerTestSupport.java | 10 +- .../presentation/EventControllerTest.java | 66 +++--- .../MemberActionControllerTest.java | 40 ---- .../AdminBillActionControllerTest.java} | 36 ++- .../admin/AdminEventControllerTest.java | 35 +++ .../AdminMemberActionControllerTest.java | 53 +++++ 24 files changed, 656 insertions(+), 597 deletions(-) delete mode 100644 server/src/main/java/server/haengdong/presentation/ActionController.java rename server/src/main/java/server/haengdong/presentation/{BillActionController.java => admin/AdminBillActionController.java} (59%) create mode 100644 server/src/main/java/server/haengdong/presentation/admin/AdminEventController.java create mode 100644 server/src/main/java/server/haengdong/presentation/admin/AdminMemberActionController.java delete mode 100644 server/src/test/java/server/haengdong/docs/ActionControllerDocsTest.java rename server/src/test/java/server/haengdong/docs/{BillActionControllerDocsTest.java => AdminBillActionControllerDocsTest.java} (64%) create mode 100644 server/src/test/java/server/haengdong/docs/AdminEventControllerDocsTest.java create mode 100644 server/src/test/java/server/haengdong/docs/AdminMemberActionControllerDocsTest.java rename server/src/test/java/server/haengdong/presentation/{BillActionControllerTest.java => admin/AdminBillActionControllerTest.java} (68%) create mode 100644 server/src/test/java/server/haengdong/presentation/admin/AdminEventControllerTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/admin/AdminMemberActionControllerTest.java diff --git a/server/src/main/java/server/haengdong/config/AdminInterceptor.java b/server/src/main/java/server/haengdong/config/AdminInterceptor.java index a0542ed46..97bf2c774 100644 --- a/server/src/main/java/server/haengdong/config/AdminInterceptor.java +++ b/server/src/main/java/server/haengdong/config/AdminInterceptor.java @@ -23,14 +23,8 @@ public AdminInterceptor(AuthService authService, AuthenticationExtractor authent @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { - String requestURI = request.getRequestURI(); - - if (requestURI.endsWith("/login")) { - return true; // 요청을 계속 진행하도록 허용 - } - HttpMethod method = HttpMethod.valueOf(request.getMethod()); - if (HttpMethod.GET.equals(method) || HttpMethod.OPTIONS.equals(method)) { + if (HttpMethod.OPTIONS.equals(method)) { return true; } diff --git a/server/src/main/java/server/haengdong/config/WebMvcConfig.java b/server/src/main/java/server/haengdong/config/WebMvcConfig.java index d1caa176f..43f858db3 100644 --- a/server/src/main/java/server/haengdong/config/WebMvcConfig.java +++ b/server/src/main/java/server/haengdong/config/WebMvcConfig.java @@ -40,8 +40,7 @@ public void addCorsMappings(CorsRegistry registry) { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(adminInterceptor()) - .addPathPatterns("/api/**") - .excludePathPatterns("/api/events"); + .addPathPatterns("/api/admin/**"); } @Bean diff --git a/server/src/main/java/server/haengdong/presentation/ActionController.java b/server/src/main/java/server/haengdong/presentation/ActionController.java deleted file mode 100644 index 657cb567e..000000000 --- a/server/src/main/java/server/haengdong/presentation/ActionController.java +++ /dev/null @@ -1,26 +0,0 @@ -package server.haengdong.presentation; - -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RestController; -import server.haengdong.application.ActionService; -import server.haengdong.application.response.MemberBillReportAppResponse; -import server.haengdong.presentation.response.MemberBillReportsResponse; - -@RequiredArgsConstructor -@RestController -public class ActionController { - - private final ActionService actionService; - - @GetMapping("/api/events/{eventId}/actions/reports") - public ResponseEntity<MemberBillReportsResponse> getMemberBillReports(@PathVariable("eventId") String token) { - List<MemberBillReportAppResponse> memberBillReports = actionService.getMemberBillReports(token); - - return ResponseEntity.ok() - .body(MemberBillReportsResponse.of(memberBillReports)); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java b/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java index 5602e6777..924bcf32c 100644 --- a/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java +++ b/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java @@ -1,16 +1,12 @@ package server.haengdong.presentation; -import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import server.haengdong.application.BillActionDetailService; import server.haengdong.application.response.BillActionDetailsAppResponse; -import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; import server.haengdong.presentation.response.BillActionDetailsResponse; @RequiredArgsConstructor @@ -28,15 +24,4 @@ public ResponseEntity<BillActionDetailsResponse> findBillActionDetails( return ResponseEntity.ok(BillActionDetailsResponse.of(appResponse)); } - - @PutMapping("/api/events/{eventId}/bill-actions/{actionId}/fixed") - public ResponseEntity<Void> updateBillActionDetails( - @PathVariable("eventId") String token, - @PathVariable("actionId") Long actionId, - @Valid @RequestBody BillActionDetailsUpdateRequest request - ) { - billActionDetailService.updateBillActionDetails(token, actionId, request.toAppRequest()); - - return ResponseEntity.ok().build(); - } } diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java index 34261042f..57d0515e7 100644 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -11,19 +11,20 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.ActionService; import server.haengdong.application.AuthService; import server.haengdong.application.EventService; import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.MemberBillReportAppResponse; import server.haengdong.infrastructure.auth.CookieProperties; import server.haengdong.presentation.request.EventLoginRequest; import server.haengdong.presentation.request.EventSaveRequest; -import server.haengdong.presentation.request.MemberNamesUpdateRequest; import server.haengdong.presentation.response.ActionsResponse; import server.haengdong.presentation.response.EventDetailResponse; import server.haengdong.presentation.response.EventResponse; +import server.haengdong.presentation.response.MemberBillReportsResponse; import server.haengdong.presentation.response.MembersResponse; import server.haengdong.presentation.response.StepsResponse; @@ -36,18 +37,7 @@ public class EventController { private final EventService eventService; private final AuthService authService; private final CookieProperties cookieProperties; - - @PostMapping("/api/events") - public ResponseEntity<EventResponse> saveEvent(@Valid @RequestBody EventSaveRequest request) { - EventResponse eventResponse = EventResponse.of(eventService.saveEvent(request.toAppRequest())); - - String jwtToken = authService.createToken(eventResponse.eventId()); - - ResponseCookie responseCookie = createResponseCookie(jwtToken); - return ResponseEntity.ok() - .header(HttpHeaders.SET_COOKIE, responseCookie.toString()) - .body(eventResponse); - } + private final ActionService actionService; @GetMapping("/api/events/{eventId}") public ResponseEntity<EventDetailResponse> findEvent(@PathVariable("eventId") String token) { @@ -78,14 +68,24 @@ public ResponseEntity<MembersResponse> findAllMembers(@PathVariable("eventId") S return ResponseEntity.ok(response); } - @PutMapping("/api/events/{eventId}/members/nameChange") - public ResponseEntity<Void> updateMember( - @PathVariable("eventId") String token, - @Valid @RequestBody MemberNamesUpdateRequest request - ) { - eventService.updateMember(token, request.toAppRequest()); + @GetMapping("/api/events/{eventId}/reports") + public ResponseEntity<MemberBillReportsResponse> getMemberBillReports(@PathVariable("eventId") String token) { + List<MemberBillReportAppResponse> memberBillReports = actionService.getMemberBillReports(token); - return ResponseEntity.ok().build(); + return ResponseEntity.ok() + .body(MemberBillReportsResponse.of(memberBillReports)); + } + + @PostMapping("/api/events") + public ResponseEntity<EventResponse> saveEvent(@Valid @RequestBody EventSaveRequest request) { + EventResponse eventResponse = EventResponse.of(eventService.saveEvent(request.toAppRequest())); + + String jwtToken = authService.createToken(eventResponse.eventId()); + + ResponseCookie responseCookie = createResponseCookie(jwtToken); + return ResponseEntity.ok() + .header(HttpHeaders.SET_COOKIE, responseCookie.toString()) + .body(eventResponse); } @PostMapping("/api/events/{eventId}/login") @@ -102,11 +102,6 @@ public ResponseEntity<Void> loginEvent( .build(); } - @PostMapping("/api/events/{eventId}/auth") - public ResponseEntity<Void> authenticate(@PathVariable("eventId") String token) { - return ResponseEntity.ok().build(); - } - private ResponseCookie createResponseCookie(String token) { return ResponseCookie.from(authService.getTokenName(), token) .httpOnly(cookieProperties.httpOnly()) diff --git a/server/src/main/java/server/haengdong/presentation/MemberActionController.java b/server/src/main/java/server/haengdong/presentation/MemberActionController.java index 1703245f7..3a20339fd 100644 --- a/server/src/main/java/server/haengdong/presentation/MemberActionController.java +++ b/server/src/main/java/server/haengdong/presentation/MemberActionController.java @@ -3,15 +3,11 @@ import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import server.haengdong.application.MemberActionService; import server.haengdong.application.response.CurrentMemberAppResponse; -import server.haengdong.presentation.request.MemberActionsSaveRequest; import server.haengdong.presentation.response.CurrentMembersResponse; @RequiredArgsConstructor @@ -20,16 +16,6 @@ public class MemberActionController { private final MemberActionService memberActionService; - @PostMapping("/api/events/{eventId}/member-actions") - public ResponseEntity<Void> saveMemberAction( - @PathVariable("eventId") String token, - @RequestBody MemberActionsSaveRequest request - ) { - memberActionService.saveMemberAction(token, request.toAppRequest()); - - return ResponseEntity.ok().build(); - } - @GetMapping("/api/events/{eventId}/members/current") public ResponseEntity<CurrentMembersResponse> getCurrentMembers(@PathVariable("eventId") String token) { List<CurrentMemberAppResponse> currentMembers = memberActionService.getCurrentMembers(token); @@ -37,24 +23,4 @@ public ResponseEntity<CurrentMembersResponse> getCurrentMembers(@PathVariable("e return ResponseEntity.ok() .body(CurrentMembersResponse.of(currentMembers)); } - - @DeleteMapping("/api/events/{eventId}/members/{memberName}") - public ResponseEntity<Void> deleteMember( - @PathVariable("eventId") String token, - @PathVariable("memberName") String memberName - ) { - memberActionService.deleteMember(token, memberName); - - return ResponseEntity.ok().build(); - } - - @DeleteMapping("/api/events/{eventId}/member-actions/{actionId}") - public ResponseEntity<Void> deleteMemberAction( - @PathVariable("eventId") String token, - @PathVariable("actionId") Long actionId - ) { - memberActionService.deleteMemberAction(token, actionId); - - return ResponseEntity.ok().build(); - } } diff --git a/server/src/main/java/server/haengdong/presentation/BillActionController.java b/server/src/main/java/server/haengdong/presentation/admin/AdminBillActionController.java similarity index 59% rename from server/src/main/java/server/haengdong/presentation/BillActionController.java rename to server/src/main/java/server/haengdong/presentation/admin/AdminBillActionController.java index 56e99337d..f3e66cdb9 100644 --- a/server/src/main/java/server/haengdong/presentation/BillActionController.java +++ b/server/src/main/java/server/haengdong/presentation/admin/AdminBillActionController.java @@ -1,4 +1,4 @@ -package server.haengdong.presentation; +package server.haengdong.presentation.admin; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -9,28 +9,30 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.BillActionDetailService; import server.haengdong.application.BillActionService; +import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; import server.haengdong.presentation.request.BillActionUpdateRequest; import server.haengdong.presentation.request.BillActionsSaveRequest; @RequiredArgsConstructor @RestController -public class BillActionController { +public class AdminBillActionController { private final BillActionService billActionService; + private final BillActionDetailService billActionDetailService; - @PostMapping("/api/events/{eventId}/bill-actions") + @PostMapping("/api/admin/events/{eventId}/bill-actions") public ResponseEntity<Void> saveAllBillAction( @PathVariable("eventId") String token, @Valid @RequestBody BillActionsSaveRequest request ) { billActionService.saveAllBillAction(token, request.toAppRequests()); - return ResponseEntity.ok() - .build(); + return ResponseEntity.ok().build(); } - @PutMapping("/api/events/{eventId}/bill-actions/{actionId}") + @PutMapping("/api/admin/events/{eventId}/bill-actions/{actionId}") public ResponseEntity<Void> updateBillAction( @PathVariable("eventId") String token, @PathVariable("actionId") Long actionId, @@ -38,18 +40,27 @@ public ResponseEntity<Void> updateBillAction( ) { billActionService.updateBillAction(token, actionId, request.toAppResponse()); - return ResponseEntity.ok() - .build(); + return ResponseEntity.ok().build(); } - @DeleteMapping("/api/events/{eventId}/bill-actions/{actionId}") + @PutMapping("/api/admin/events/{eventId}/bill-actions/{actionId}/fixed") + public ResponseEntity<Void> updateBillActionDetails( + @PathVariable("eventId") String token, + @PathVariable("actionId") Long actionId, + @Valid @RequestBody BillActionDetailsUpdateRequest request + ) { + billActionDetailService.updateBillActionDetails(token, actionId, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } + + @DeleteMapping("/api/admin/events/{eventId}/bill-actions/{actionId}") public ResponseEntity<Void> deleteBillAction( @PathVariable("eventId") String token, @PathVariable("actionId") Long actionId ) { billActionService.deleteBillAction(token, actionId); - return ResponseEntity.ok() - .build(); + return ResponseEntity.ok().build(); } } diff --git a/server/src/main/java/server/haengdong/presentation/admin/AdminEventController.java b/server/src/main/java/server/haengdong/presentation/admin/AdminEventController.java new file mode 100644 index 000000000..aa4a8a278 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/admin/AdminEventController.java @@ -0,0 +1,39 @@ +package server.haengdong.presentation.admin; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.EventService; +import server.haengdong.infrastructure.auth.CookieProperties; +import server.haengdong.presentation.request.MemberNamesUpdateRequest; + +@Slf4j +@RequiredArgsConstructor +@EnableConfigurationProperties(CookieProperties.class) +@RestController +public class AdminEventController { + + private final EventService eventService; + + @PostMapping("/api/admin/events/{eventId}/auth") + public ResponseEntity<Void> authenticate(@PathVariable("eventId") String token) { + return ResponseEntity.ok().build(); + } + + @PutMapping("/api/admin/events/{eventId}/members/nameChange") + public ResponseEntity<Void> updateMember( + @PathVariable("eventId") String token, + @Valid @RequestBody MemberNamesUpdateRequest request + ) { + eventService.updateMember(token, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/admin/AdminMemberActionController.java b/server/src/main/java/server/haengdong/presentation/admin/AdminMemberActionController.java new file mode 100644 index 000000000..c45f18405 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/admin/AdminMemberActionController.java @@ -0,0 +1,48 @@ +package server.haengdong.presentation.admin; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.MemberActionService; +import server.haengdong.presentation.request.MemberActionsSaveRequest; + +@RequiredArgsConstructor +@RestController +public class AdminMemberActionController { + + private final MemberActionService memberActionService; + + @PostMapping("/api/admin/events/{eventId}/member-actions") + public ResponseEntity<Void> saveMemberAction( + @PathVariable("eventId") String token, + @RequestBody MemberActionsSaveRequest request + ) { + memberActionService.saveMemberAction(token, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } + + @DeleteMapping("/api/admin/events/{eventId}/members/{memberName}") + public ResponseEntity<Void> deleteMember( + @PathVariable("eventId") String token, + @PathVariable("memberName") String memberName + ) { + memberActionService.deleteMember(token, memberName); + + return ResponseEntity.ok().build(); + } + + @DeleteMapping("/api/admin/events/{eventId}/member-actions/{actionId}") + public ResponseEntity<Void> deleteMemberAction( + @PathVariable("eventId") String token, + @PathVariable("actionId") Long actionId + ) { + memberActionService.deleteMemberAction(token, actionId); + + return ResponseEntity.ok().build(); + } +} diff --git a/server/src/test/java/server/haengdong/docs/ActionControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/ActionControllerDocsTest.java deleted file mode 100644 index 39c2d0bb8..000000000 --- a/server/src/test/java/server/haengdong/docs/ActionControllerDocsTest.java +++ /dev/null @@ -1,70 +0,0 @@ -package server.haengdong.docs; - -import static org.hamcrest.Matchers.equalTo; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; -import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; -import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; -import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; -import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.http.MediaType; -import org.springframework.restdocs.payload.JsonFieldType; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers; -import server.haengdong.application.ActionService; -import server.haengdong.application.response.MemberBillReportAppResponse; -import server.haengdong.presentation.ActionController; - -class ActionControllerDocsTest extends RestDocsSupport { - - private final ActionService actionService = mock(ActionService.class); - - @Override - protected Object initController() { - return new ActionController(actionService); - } - - @DisplayName("참여자별 정산 현황을 조회한다.") - @Test - void getMemberBillReports() throws Exception { - List<MemberBillReportAppResponse> memberBillReportAppResponses = List.of( - new MemberBillReportAppResponse("소하", 20_000L), new MemberBillReportAppResponse("토다리", 200_000L)); - - given(actionService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); - - mockMvc.perform(get("/api/events/{eventId}/actions/reports", "망쵸토큰") - .accept(MediaType.APPLICATION_JSON)) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].name").value(equalTo("소하"))) - .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].price").value(equalTo(20_000))) - .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].name").value(equalTo("토다리"))) - .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].price").value(equalTo(200_000))) - .andDo( - document("getMemberBillReports", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - responseFields( - fieldWithPath("reports").type(JsonFieldType.ARRAY).description("전체 정산 현황 목록"), - fieldWithPath("reports[0].name").type(JsonFieldType.STRING) - .description("참여자 이름"), - fieldWithPath("reports[0].price").type(JsonFieldType.NUMBER) - .description("참여자 정산 금액") - )) - ); - } -} diff --git a/server/src/test/java/server/haengdong/docs/BillActionControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/AdminBillActionControllerDocsTest.java similarity index 64% rename from server/src/test/java/server/haengdong/docs/BillActionControllerDocsTest.java rename to server/src/test/java/server/haengdong/docs/AdminBillActionControllerDocsTest.java index 7ed6fe6c4..705adaa5c 100644 --- a/server/src/test/java/server/haengdong/docs/BillActionControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/AdminBillActionControllerDocsTest.java @@ -22,19 +22,24 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; +import org.springframework.restdocs.payload.JsonFieldType; +import server.haengdong.application.BillActionDetailService; import server.haengdong.application.BillActionService; -import server.haengdong.presentation.BillActionController; +import server.haengdong.presentation.admin.AdminBillActionController; +import server.haengdong.presentation.request.BillActionDetailUpdateRequest; +import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; import server.haengdong.presentation.request.BillActionSaveRequest; import server.haengdong.presentation.request.BillActionUpdateRequest; import server.haengdong.presentation.request.BillActionsSaveRequest; -class BillActionControllerDocsTest extends RestDocsSupport { +class AdminBillActionControllerDocsTest extends RestDocsSupport { private final BillActionService billActionService = mock(BillActionService.class); + private final BillActionDetailService billActionDetailService = mock(BillActionDetailService.class); @Override protected Object initController() { - return new BillActionController(billActionService); + return new AdminBillActionController(billActionService, billActionDetailService); } @DisplayName("지출 내역을 생성한다.") @@ -49,7 +54,7 @@ void saveAllBillAction() throws Exception { String requestBody = objectMapper.writeValueAsString(request); String eventId = "쿠키토큰"; - mockMvc.perform(post("/api/events/{eventId}/bill-actions", eventId) + mockMvc.perform(post("/api/admin/events/{eventId}/bill-actions", eventId) .contentType(MediaType.APPLICATION_JSON) .cookie(EVENT_COOKIE) .content(requestBody)) @@ -80,7 +85,7 @@ void updateBillAction() throws Exception { String requestBody = objectMapper.writeValueAsString(request); String eventId = "웨디토큰"; - mockMvc.perform(put("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1L) + mockMvc.perform(put("/api/admin/events/{eventId}/bill-actions/{actionId}", eventId, 1L) .cookie(EVENT_COOKIE) .contentType(MediaType.APPLICATION_JSON) .content(requestBody)) @@ -103,12 +108,55 @@ void updateBillAction() throws Exception { )); } + @DisplayName("참여자별 지출 금액을 수정한다.") + @Test + void updateBillActionDetailsTest() throws Exception { + List<BillActionDetailUpdateRequest> billActionDetailUpdateRequests = List.of( + new BillActionDetailUpdateRequest("소하", 10000L, true), + new BillActionDetailUpdateRequest("웨디", 20000L, true) + ); + BillActionDetailsUpdateRequest request = new BillActionDetailsUpdateRequest( + billActionDetailUpdateRequests); + + String json = objectMapper.writeValueAsString(request); + + mockMvc.perform(put("/api/admin/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L) + .cookie(EVENT_COOKIE) + .contentType(MediaType.APPLICATION_JSON) + .content(json)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("updateBillActionDetailsTest", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("actionId").description("액션 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), + requestFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("전체 정산 수정 요청 목록"), + fieldWithPath("members[0].name").type(JsonFieldType.STRING) + .description("참여자 이름"), + fieldWithPath("members[0].price").type(JsonFieldType.NUMBER) + .description("참여자 정산 금액"), + fieldWithPath("members[0].isFixed").type(JsonFieldType.BOOLEAN) + .description("참여자 정산 금액 수정 여부") + ) + ) + ); + } + @DisplayName("지출 내역을 삭제한다.") @Test void deleteBillAction() throws Exception { String eventId = "토다리토큰"; - mockMvc.perform(delete("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1) + mockMvc.perform(delete("/api/admin/events/{eventId}/bill-actions/{actionId}", eventId, 1) .cookie(EVENT_COOKIE) ) .andDo(print()) diff --git a/server/src/test/java/server/haengdong/docs/AdminEventControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/AdminEventControllerDocsTest.java new file mode 100644 index 000000000..956035e92 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/AdminEventControllerDocsTest.java @@ -0,0 +1,99 @@ +package server.haengdong.docs; + +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; +import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.restdocs.payload.JsonFieldType; +import server.haengdong.application.EventService; +import server.haengdong.presentation.admin.AdminEventController; +import server.haengdong.presentation.request.MemberNameUpdateRequest; +import server.haengdong.presentation.request.MemberNamesUpdateRequest; + +public class AdminEventControllerDocsTest extends RestDocsSupport { + + private final EventService eventService = mock(EventService.class); + + @Override + protected Object initController() { + return new AdminEventController(eventService); + } + + @DisplayName("행사 어드민 권한을 확인한다.") + @Test + void authenticateTest() throws Exception { + String token = "TOKEN"; + mockMvc.perform(post("/api/admin/events/{eventId}/auth", token) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + + .andDo( + document("authenticateEvent", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰").optional() + ) + ) + ); + } + + @DisplayName("행사 참여 인원의 이름을 수정한다.") + @Test + void updateMember() throws Exception { + String token = "TOKEN"; + MemberNamesUpdateRequest memberNameUpdateRequest = new MemberNamesUpdateRequest(List.of( + new MemberNameUpdateRequest("토다링", "토쟁이"), + new MemberNameUpdateRequest("감자", "고구마") + )); + + String requestBody = objectMapper.writeValueAsString(memberNameUpdateRequest); + + mockMvc.perform(put("/api/admin/events/{eventId}/members/nameChange", token) + .cookie(EVENT_COOKIE) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("updateEventMemberName", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), + requestFields( + fieldWithPath("members").type(JsonFieldType.ARRAY).description("수정할 참여자 목록"), + fieldWithPath("members[].before").type(JsonFieldType.STRING) + .description("수정 전 참여자 이름"), + fieldWithPath("members[].after").type(JsonFieldType.STRING) + .description("수정 후 참여자 이름") + ) + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/docs/AdminMemberActionControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/AdminMemberActionControllerDocsTest.java new file mode 100644 index 000000000..f8a4f7dbd --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/AdminMemberActionControllerDocsTest.java @@ -0,0 +1,121 @@ +package server.haengdong.docs; + +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; +import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.restdocs.payload.JsonFieldType; +import server.haengdong.application.MemberActionService; +import server.haengdong.presentation.admin.AdminMemberActionController; +import server.haengdong.presentation.request.MemberActionsSaveRequest; + +public class AdminMemberActionControllerDocsTest extends RestDocsSupport { + + private final MemberActionService memberActionService = mock(MemberActionService.class); + + @Override + protected Object initController() { + return new AdminMemberActionController(memberActionService); + } + + @DisplayName("참여자 행동을 추가한다.") + @Test + void saveMemberActionTest() throws Exception { + MemberActionsSaveRequest memberActionsSaveRequest = new MemberActionsSaveRequest( + List.of("웨디", "소하", "토다리", "쿠키"), "IN"); + + String requestBody = objectMapper.writeValueAsString(memberActionsSaveRequest); + + mockMvc.perform(post("/api/admin/events/{eventId}/member-actions", "망쵸토큰") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("createMemberAction", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("토큰 토큰") + ), + requestFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("액션 대상 참여자 목록"), + fieldWithPath("status").type(JsonFieldType.STRING) + .description("참여자 액션 상태 [IN(늦참), OUT(탈주)]") + ) + ) + ); + } + + @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") + @Test + void deleteMemberAction() throws Exception { + String eventId = "망쵸토큰"; + Long actionId = 2L; + + mockMvc.perform(delete("/api/admin/events/{eventId}/member-actions/{actionId}", eventId, actionId) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("deleteMemberAction", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("actionId").description("액션 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자용 토큰") + ) + ) + ); + } + + @DisplayName("행사의 전체 참여자 중에서 특정 참여자의 맴버 액션을 전부 삭제한다.") + @Test + void deleteMember() throws Exception { + String eventId = "망쵸토큰"; + String memberName = "행동대장"; + + mockMvc.perform(delete("/api/admin/events/{eventId}/members/{memberName}", eventId, memberName) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("deleteAllMemberActionByName", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("memberName").description("행사 참여자 이름") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자용 토큰") + ) + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java index f492195f3..d79bd2c02 100644 --- a/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java @@ -8,12 +8,10 @@ import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; -import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; @@ -25,14 +23,11 @@ import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.springframework.http.MediaType; import org.springframework.restdocs.payload.JsonFieldType; import server.haengdong.application.BillActionDetailService; import server.haengdong.application.response.BillActionDetailAppResponse; import server.haengdong.application.response.BillActionDetailsAppResponse; import server.haengdong.presentation.BillActionDetailController; -import server.haengdong.presentation.request.BillActionDetailUpdateRequest; -import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; public class BillActionDetailControllerDocsTest extends RestDocsSupport { @@ -81,47 +76,4 @@ void findBillActionDetailsTest() throws Exception { ) ); } - - @DisplayName("참여자별 지출 금액을 수정한다.") - @Test - void updateBillActionDetailsTest() throws Exception { - List<BillActionDetailUpdateRequest> billActionDetailUpdateRequests = List.of( - new BillActionDetailUpdateRequest("소하", 10000L, true), - new BillActionDetailUpdateRequest("웨디", 20000L, true) - ); - BillActionDetailsUpdateRequest request = new BillActionDetailsUpdateRequest( - billActionDetailUpdateRequests); - - String json = objectMapper.writeValueAsString(request); - - mockMvc.perform(put("/api/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L) - .cookie(EVENT_COOKIE) - .contentType(MediaType.APPLICATION_JSON) - .content(json)) - .andDo(print()) - .andExpect(status().isOk()) - .andDo( - document("updateBillActionDetailsTest", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID"), - parameterWithName("actionId").description("액션 ID") - ), - requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") - ), - requestFields( - fieldWithPath("members").type(JsonFieldType.ARRAY) - .description("전체 정산 수정 요청 목록"), - fieldWithPath("members[0].name").type(JsonFieldType.STRING) - .description("참여자 이름"), - fieldWithPath("members[0].price").type(JsonFieldType.NUMBER) - .description("참여자 정산 금액"), - fieldWithPath("members[0].isFixed").type(JsonFieldType.BOOLEAN) - .description("참여자 정산 금액 수정 여부") - ) - ) - ); - } } diff --git a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java index 88de2a3a6..202b64fcf 100644 --- a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java @@ -6,12 +6,10 @@ import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; -import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; import static org.springframework.restdocs.cookies.CookieDocumentation.responseCookies; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; @@ -24,7 +22,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; import java.time.Duration; import java.util.List; @@ -32,6 +29,8 @@ import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import server.haengdong.application.ActionService; import server.haengdong.application.AuthService; import server.haengdong.application.EventService; import server.haengdong.application.request.EventAppRequest; @@ -39,62 +38,25 @@ import server.haengdong.application.response.ActionAppResponse.ActionType; import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.application.response.MemberBillReportAppResponse; import server.haengdong.application.response.MembersAppResponse; import server.haengdong.infrastructure.auth.CookieProperties; import server.haengdong.presentation.EventController; import server.haengdong.presentation.request.EventLoginRequest; import server.haengdong.presentation.request.EventSaveRequest; -import server.haengdong.presentation.request.MemberNameUpdateRequest; -import server.haengdong.presentation.request.MemberNamesUpdateRequest; public class EventControllerDocsTest extends RestDocsSupport { private final EventService eventService = mock(EventService.class); private final AuthService authService = mock(AuthService.class); + private final ActionService actionService = mock(ActionService.class); private final CookieProperties cookieProperties = new CookieProperties( true, true, "domain", "path", "none", Duration.ofDays(7) ); @Override protected Object initController() { - return new EventController(eventService, authService, cookieProperties); - } - - @DisplayName("이벤트를 생성한다.") - @Test - void saveEvent() throws Exception { - EventSaveRequest eventSaveRequest = new EventSaveRequest("토다리", "0987"); - String requestBody = objectMapper.writeValueAsString(eventSaveRequest); - String eventId = "쿠키 토큰"; - EventAppResponse eventAppResponse = new EventAppResponse(eventId); - given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); - given(authService.createToken(eventId)).willReturn("jwtToken"); - given(authService.getTokenName()).willReturn("eventToken"); - - mockMvc.perform(post("/api/events") - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(cookie().value("eventToken", "jwtToken")) - .andExpect(jsonPath("$.eventId").value("쿠키 토큰")) - .andDo( - document("createEvent", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - requestFields( - fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름"), - fieldWithPath("password").type(JsonFieldType.STRING).description("행사 비밀 번호") - ), - responseFields( - fieldWithPath("eventId").type(JsonFieldType.STRING) - .description("행사 ID") - ), - responseCookies( - cookieWithName("eventToken").description("행사 관리자용 토큰") - ) - ) - ); + return new EventController(eventService, authService, cookieProperties, actionService); } @DisplayName("토큰으로 행사를 조회한다.") @@ -149,77 +111,6 @@ void findAllMembersTest() throws Exception { ); } - @DisplayName("행사 참여 인원의 이름을 수정한다.") - @Test - void updateMember() throws Exception { - String token = "TOKEN"; - MemberNamesUpdateRequest memberNameUpdateRequest = new MemberNamesUpdateRequest(List.of( - new MemberNameUpdateRequest("토다링", "토쟁이"), - new MemberNameUpdateRequest("감자", "고구마") - )); - - String requestBody = objectMapper.writeValueAsString(memberNameUpdateRequest); - - mockMvc.perform(put("/api/events/{eventId}/members/nameChange", token) - .cookie(EVENT_COOKIE) - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) - .andDo(print()) - .andExpect(status().isOk()) - .andDo( - document("updateEventMemberName", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") - ), - requestFields( - fieldWithPath("members").type(JsonFieldType.ARRAY).description("수정할 참여자 목록"), - fieldWithPath("members[].before").type(JsonFieldType.STRING) - .description("수정 전 참여자 이름"), - fieldWithPath("members[].after").type(JsonFieldType.STRING) - .description("수정 후 참여자 이름") - ) - ) - ); - } - - @DisplayName("행사 어드민이 로그인한다.") - @Test - void loginEvent() throws Exception { - String token = "TOKEN"; - EventLoginRequest eventLoginRequest = new EventLoginRequest("1234"); - String requestBody = objectMapper.writeValueAsString(eventLoginRequest); - given(authService.createToken(token)).willReturn("jwtToken"); - given(authService.getTokenName()).willReturn("eventToken"); - - mockMvc.perform(post("/api/events/{eventId}/login", token) - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) - .andDo(print()) - .andExpect(cookie().value("eventToken", "jwtToken")) - .andExpect(status().isOk()) - .andDo( - document("eventLogin", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - requestFields( - fieldWithPath("password").type(JsonFieldType.STRING) - .description("행사 비밀 번호") - ), - responseCookies( - cookieWithName("eventToken").description("행사 관리자용 토큰") - ) - ) - ); - } - @DisplayName("행사 전체 액션 이력 조회") @Test void findActions() throws Exception { @@ -356,24 +247,104 @@ void findActions2() throws Exception { ); } - @DisplayName("행사 어드민 권한을 확인한다.") + @DisplayName("참여자별 정산 현황을 조회한다.") @Test - void authenticateTest() throws Exception { - String token = "TOKEN"; - mockMvc.perform(post("/api/events/{eventId}/auth", token) - .cookie(EVENT_COOKIE)) + void getMemberBillReports() throws Exception { + List<MemberBillReportAppResponse> memberBillReportAppResponses = List.of( + new MemberBillReportAppResponse("소하", 20_000L), new MemberBillReportAppResponse("토다리", 200_000L)); + + given(actionService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/reports", "망쵸토큰") + .accept(MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].name").value(equalTo("소하"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].price").value(equalTo(20_000))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].name").value(equalTo("토다리"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].price").value(equalTo(200_000))) + .andDo( + document("getMemberBillReports", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("reports").type(JsonFieldType.ARRAY).description("전체 정산 현황 목록"), + fieldWithPath("reports[0].name").type(JsonFieldType.STRING) + .description("참여자 이름"), + fieldWithPath("reports[0].price").type(JsonFieldType.NUMBER) + .description("참여자 정산 금액") + )) + ); + } + + @DisplayName("이벤트를 생성한다.") + @Test + void saveEvent() throws Exception { + EventSaveRequest eventSaveRequest = new EventSaveRequest("토다리", "0987"); + String requestBody = objectMapper.writeValueAsString(eventSaveRequest); + String eventId = "쿠키 토큰"; + EventAppResponse eventAppResponse = new EventAppResponse(eventId); + given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); + given(authService.createToken(eventId)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("eventToken"); + mockMvc.perform(post("/api/events") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(jsonPath("$.eventId").value("쿠키 토큰")) .andDo( - document("authenticateEvent", + document("createEvent", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + requestFields( + fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름"), + fieldWithPath("password").type(JsonFieldType.STRING).description("행사 비밀 번호") + ), + responseFields( + fieldWithPath("eventId").type(JsonFieldType.STRING) + .description("행사 ID") + ), + responseCookies( + cookieWithName("eventToken").description("행사 관리자용 토큰") + ) + ) + ); + } + + @DisplayName("행사 어드민이 로그인한다.") + @Test + void loginEvent() throws Exception { + String token = "TOKEN"; + EventLoginRequest eventLoginRequest = new EventLoginRequest("1234"); + String requestBody = objectMapper.writeValueAsString(eventLoginRequest); + given(authService.createToken(token)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("eventToken"); + + mockMvc.perform(post("/api/events/{eventId}/login", token) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(status().isOk()) + .andDo( + document("eventLogin", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), pathParameters( parameterWithName("eventId").description("행사 ID") ), - requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰").optional() + requestFields( + fieldWithPath("password").type(JsonFieldType.STRING) + .description("행사 비밀 번호") + ), + responseCookies( + cookieWithName("eventToken").description("행사 관리자용 토큰") ) ) ); diff --git a/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java index afd766c8f..ace03c5ef 100644 --- a/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java @@ -4,24 +4,18 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; -import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; -import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; -import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; import java.util.List; import org.junit.jupiter.api.DisplayName; @@ -31,7 +25,6 @@ import server.haengdong.application.MemberActionService; import server.haengdong.application.response.CurrentMemberAppResponse; import server.haengdong.presentation.MemberActionController; -import server.haengdong.presentation.request.MemberActionsSaveRequest; public class MemberActionControllerDocsTest extends RestDocsSupport { @@ -42,40 +35,6 @@ protected Object initController() { return new MemberActionController(memberActionService); } - @DisplayName("참여자 행동을 추가한다.") - @Test - void saveMemberActionTest() throws Exception { - MemberActionsSaveRequest memberActionsSaveRequest = new MemberActionsSaveRequest( - List.of("웨디", "소하", "토다리", "쿠키"), "IN"); - - String requestBody = objectMapper.writeValueAsString(memberActionsSaveRequest); - - mockMvc.perform(post("/api/events/{eventId}/member-actions", "망쵸토큰") - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody) - .cookie(EVENT_COOKIE)) - .andDo(print()) - .andExpect(status().isOk()) - .andDo( - document("createMemberAction", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - requestCookies( - cookieWithName("eventToken").description("토큰 토큰") - ), - requestFields( - fieldWithPath("members").type(JsonFieldType.ARRAY) - .description("액션 대상 참여자 목록"), - fieldWithPath("status").type(JsonFieldType.STRING) - .description("참여자 액션 상태 [IN(늦참), OUT(탈주)]") - ) - ) - ); - } - @DisplayName("현재 참여 인원을 조회합니다.") @Test void getCurrentMembers() throws Exception { @@ -104,54 +63,4 @@ void getCurrentMembers() throws Exception { ) ); } - - @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") - @Test - void deleteMemberAction() throws Exception { - String eventId = "망쵸토큰"; - Long actionId = 2L; - - mockMvc.perform(delete("/api/events/{eventId}/member-actions/{actionId}", eventId, actionId) - .cookie(EVENT_COOKIE)) - .andDo(print()) - .andExpect(status().isOk()) - .andDo( - document("deleteMemberAction", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID"), - parameterWithName("actionId").description("액션 ID") - ), - requestCookies( - cookieWithName("eventToken").description("행사 관리자용 토큰") - ) - ) - ); - } - - @DisplayName("행사의 전체 참여자 중에서 특정 참여자의 맴버 액션을 전부 삭제한다.") - @Test - void deleteMember() throws Exception { - String eventId = "망쵸토큰"; - String memberName = "행동대장"; - - mockMvc.perform(delete("/api/events/{eventId}/members/{memberName}", eventId, memberName) - .cookie(EVENT_COOKIE)) - .andDo(print()) - .andExpect(status().isOk()) - .andDo( - document("deleteAllMemberActionByName", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID"), - parameterWithName("memberName").description("행사 참여자 이름") - ), - requestCookies( - cookieWithName("eventToken").description("행사 관리자용 토큰") - ) - ) - ); - } } diff --git a/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java index 1de5889b5..0fa3311b3 100644 --- a/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java @@ -1,36 +1,4 @@ package server.haengdong.presentation; -import static org.hamcrest.Matchers.equalTo; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers; -import server.haengdong.application.response.MemberBillReportAppResponse; - class ActionControllerTest extends ControllerTestSupport { - - @DisplayName("참여자별 정산 현황을 조회한다.") - @Test - void getMemberBillReports() throws Exception { - List<MemberBillReportAppResponse> memberBillReportAppResponses = List.of( - new MemberBillReportAppResponse("소하", 20_000L), new MemberBillReportAppResponse("토다리", 200_000L)); - - given(actionService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); - - mockMvc.perform(get("/api/events/{eventId}/actions/reports", "망쵸토큰") - .accept(MediaType.APPLICATION_JSON)) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].name").value(equalTo("소하"))) - .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].price").value(equalTo(20_000))) - .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].name").value(equalTo("토다리"))) - .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].price").value(equalTo(200_000))); - } } diff --git a/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java index 6b595ee27..f4e65d4f0 100644 --- a/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java @@ -4,19 +4,14 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.given; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.springframework.http.MediaType; import server.haengdong.application.response.BillActionDetailAppResponse; import server.haengdong.application.response.BillActionDetailsAppResponse; -import server.haengdong.presentation.request.BillActionDetailUpdateRequest; -import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; class BillActionDetailControllerTest extends ControllerTestSupport { @@ -34,23 +29,4 @@ void findBillActionDetails() throws Exception { .andExpect(jsonPath("$.members[0].name").value("토다리")) .andExpect(jsonPath("$.members[0].price").value(1000L)); } - - @DisplayName("참여자별 지출 금액을 수정한다.") - @Test - void updateBillActionDetailsTest() throws Exception { - List<BillActionDetailUpdateRequest> billActionDetailUpdateRequests = List.of( - new BillActionDetailUpdateRequest("소하", 10000L, true), - new BillActionDetailUpdateRequest("웨디", 20000L, true) - ); - BillActionDetailsUpdateRequest request = new BillActionDetailsUpdateRequest( - billActionDetailUpdateRequests); - - String json = objectMapper.writeValueAsString(request); - - mockMvc.perform(put("/api/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L) - .contentType(MediaType.APPLICATION_JSON) - .content(json)) - .andDo(print()) - .andExpect(status().isOk()); - } } diff --git a/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java b/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java index 46489b1a5..c20043381 100644 --- a/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java +++ b/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java @@ -14,18 +14,22 @@ import server.haengdong.application.BillActionService; import server.haengdong.application.EventService; import server.haengdong.application.MemberActionService; +import server.haengdong.presentation.admin.AdminBillActionController; +import server.haengdong.presentation.admin.AdminEventController; +import server.haengdong.presentation.admin.AdminMemberActionController; @WebMvcTest( controllers = { + AdminEventController.class, + AdminBillActionController.class, + AdminMemberActionController.class, EventController.class, - ActionController.class, - BillActionController.class, MemberActionController.class, BillActionDetailController.class }, excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {WebMvcConfigurer.class})} ) -abstract class ControllerTestSupport { +public abstract class ControllerTestSupport { @Autowired protected MockMvc mockMvc; diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java index fcfe48d01..a45c73230 100644 --- a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java @@ -1,11 +1,11 @@ package server.haengdong.presentation; +import static org.hamcrest.Matchers.equalTo; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.given; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; @@ -15,38 +15,18 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import server.haengdong.application.request.EventAppRequest; import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.application.response.MemberBillReportAppResponse; import server.haengdong.application.response.MembersAppResponse; import server.haengdong.presentation.request.EventLoginRequest; import server.haengdong.presentation.request.EventSaveRequest; -import server.haengdong.presentation.request.MemberNameUpdateRequest; -import server.haengdong.presentation.request.MemberNamesUpdateRequest; class EventControllerTest extends ControllerTestSupport { - @DisplayName("이벤트를 생성한다.") - @Test - void saveEvent() throws Exception { - EventSaveRequest eventSaveRequest = new EventSaveRequest("토다리", "0987"); - String requestBody = objectMapper.writeValueAsString(eventSaveRequest); - String eventId = "망쵸토큰"; - EventAppResponse eventAppResponse = new EventAppResponse(eventId); - given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); - given(authService.createToken(eventId)).willReturn("jwtToken"); - given(authService.getTokenName()).willReturn("eventToken"); - - mockMvc.perform(post("/api/events") - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(cookie().value("eventToken", "jwtToken")) - .andExpect(jsonPath("$.eventId").value("망쵸토큰")); - } - @DisplayName("토큰으로 행사를 조회한다.") @Test void findEventTest() throws Exception { @@ -74,22 +54,42 @@ void findAllMembersTest() throws Exception { .andExpect(jsonPath("$.memberNames[1]").value("쿠키")); } - @DisplayName("행사 참여 인원의 이름을 수정한다.") + @DisplayName("참여자별 정산 현황을 조회한다.") @Test - void updateMember() throws Exception { - String token = "TOKEN"; - MemberNamesUpdateRequest memberNameUpdateRequest = new MemberNamesUpdateRequest(List.of( - new MemberNameUpdateRequest("토다링", "토쟁이"), - new MemberNameUpdateRequest("감자", "고구마") - )); + void getMemberBillReports() throws Exception { + List<MemberBillReportAppResponse> memberBillReportAppResponses = List.of( + new MemberBillReportAppResponse("소하", 20_000L), new MemberBillReportAppResponse("토다리", 200_000L)); - String requestBody = objectMapper.writeValueAsString(memberNameUpdateRequest); + given(actionService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); - mockMvc.perform(put("/api/events/{eventId}/members/nameChange", token) + mockMvc.perform(get("/api/events/{eventId}/reports", "망쵸토큰") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].name").value(equalTo("소하"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].price").value(equalTo(20_000))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].name").value(equalTo("토다리"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].price").value(equalTo(200_000))); + } + + @DisplayName("이벤트를 생성한다.") + @Test + void saveEvent() throws Exception { + EventSaveRequest eventSaveRequest = new EventSaveRequest("토다리", "0987"); + String requestBody = objectMapper.writeValueAsString(eventSaveRequest); + String eventId = "망쵸토큰"; + EventAppResponse eventAppResponse = new EventAppResponse(eventId); + given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); + given(authService.createToken(eventId)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("eventToken"); + + mockMvc.perform(post("/api/events") .contentType(MediaType.APPLICATION_JSON) .content(requestBody)) .andDo(print()) - .andExpect(status().isOk()); + .andExpect(status().isOk()) + .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(jsonPath("$.eventId").value("망쵸토큰")); } @DisplayName("행사 어드민이 로그인한다.") diff --git a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java index f50c70a17..a2fd05437 100644 --- a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java @@ -3,9 +3,7 @@ import static org.hamcrest.Matchers.equalTo; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -15,25 +13,9 @@ import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; import server.haengdong.application.response.CurrentMemberAppResponse; -import server.haengdong.presentation.request.MemberActionsSaveRequest; class MemberActionControllerTest extends ControllerTestSupport { - @DisplayName("참여자 행동을 추가한다.") - @Test - void saveMemberActionTest() throws Exception { - MemberActionsSaveRequest memberActionsSaveRequest = new MemberActionsSaveRequest( - List.of("웨디", "소하", "토다리", "쿠키"), "IN"); - - String requestBody = objectMapper.writeValueAsString(memberActionsSaveRequest); - - mockMvc.perform(post("/api/events/{eventId}/member-actions", "망쵸토큰") - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) - .andDo(print()) - .andExpect(status().isOk()); - } - @DisplayName("현재 참여 인원을 조회합니다.") @Test void getCurrentMembers() throws Exception { @@ -49,26 +31,4 @@ void getCurrentMembers() throws Exception { .andExpect(jsonPath("$.memberNames[0]").value(equalTo("소하"))) .andExpect(jsonPath("$.memberNames[1]").value(equalTo("토다리"))); } - - @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") - @Test - void deleteMemberAction() throws Exception { - String eventId = "망쵸토큰"; - Long actionId = 2L; - - mockMvc.perform(delete("/api/events/{eventId}/member-actions/{actionId}", eventId, actionId)) - .andDo(print()) - .andExpect(status().isOk()); - } - - @DisplayName("행사의 전체 참여자 중에서 특정 참여자의 맴버 액션을 전부 삭제한다.") - @Test - void deleteMember() throws Exception { - String eventId = "망쵸토큰"; - String memberName = "행동대장"; - - mockMvc.perform(delete("/api/events/{eventId}/members/{memberName}", eventId, memberName)) - .andDo(print()) - .andExpect(status().isOk()); - } } diff --git a/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/admin/AdminBillActionControllerTest.java similarity index 68% rename from server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java rename to server/src/test/java/server/haengdong/presentation/admin/AdminBillActionControllerTest.java index 4420e369c..7e401d9b0 100644 --- a/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/admin/AdminBillActionControllerTest.java @@ -1,4 +1,4 @@ -package server.haengdong.presentation; +package server.haengdong.presentation.admin; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doThrow; @@ -14,11 +14,14 @@ import org.springframework.http.MediaType; import server.haengdong.exception.HaengdongErrorCode; import server.haengdong.exception.HaengdongException; +import server.haengdong.presentation.ControllerTestSupport; +import server.haengdong.presentation.request.BillActionDetailUpdateRequest; +import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; import server.haengdong.presentation.request.BillActionSaveRequest; import server.haengdong.presentation.request.BillActionUpdateRequest; import server.haengdong.presentation.request.BillActionsSaveRequest; -class BillActionControllerTest extends ControllerTestSupport { +class AdminBillActionControllerTest extends ControllerTestSupport { @DisplayName("지출 내역을 생성한다.") @Test @@ -32,7 +35,7 @@ void saveAllBillAction() throws Exception { String requestBody = objectMapper.writeValueAsString(request); String eventId = "쿠키토큰"; - mockMvc.perform(post("/api/events/{eventId}/bill-actions", eventId) + mockMvc.perform(post("/api/admin/events/{eventId}/bill-actions", eventId) .contentType(MediaType.APPLICATION_JSON) .content(requestBody)) .andDo(print()) @@ -51,7 +54,7 @@ void saveAllBillAction1() throws Exception { String requestBody = objectMapper.writeValueAsString(request); String eventId = "소하토큰"; - mockMvc.perform(post("/api/events/{eventId}/bill-actions", eventId) + mockMvc.perform(post("/api/admin/events/{eventId}/bill-actions", eventId) .contentType(MediaType.APPLICATION_JSON) .content(requestBody)) .andDo(print()) @@ -66,7 +69,7 @@ void updateBillAction() throws Exception { String requestBody = objectMapper.writeValueAsString(request); String eventId = "웨디토큰"; - mockMvc.perform(put("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1L) + mockMvc.perform(put("/api/admin/events/{eventId}/bill-actions/{actionId}", eventId, 1L) .contentType(MediaType.APPLICATION_JSON) .content(requestBody)) .andDo(print()) @@ -78,7 +81,7 @@ void updateBillAction() throws Exception { void deleteBillAction() throws Exception { String eventId = "토다리토큰"; - mockMvc.perform(delete("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1)) + mockMvc.perform(delete("/api/admin/events/{eventId}/bill-actions/{actionId}", eventId, 1)) .andDo(print()) .andExpect(status().isOk()); } @@ -90,8 +93,27 @@ void deleteBillAction1() throws Exception { doThrow(new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)) .when(billActionService).deleteBillAction(any(String.class), any(Long.class)); - mockMvc.perform(delete("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1)) + mockMvc.perform(delete("/api/admin/events/{eventId}/bill-actions/{actionId}", eventId, 1)) .andDo(print()) .andExpect(status().isBadRequest()); } + + @DisplayName("참여자별 지출 금액을 수정한다.") + @Test + void updateBillActionDetailsTest() throws Exception { + List<BillActionDetailUpdateRequest> billActionDetailUpdateRequests = List.of( + new BillActionDetailUpdateRequest("소하", 10000L, true), + new BillActionDetailUpdateRequest("웨디", 20000L, true) + ); + BillActionDetailsUpdateRequest request = new BillActionDetailsUpdateRequest( + billActionDetailUpdateRequests); + + String json = objectMapper.writeValueAsString(request); + + mockMvc.perform(put("/api/admin/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L) + .contentType(MediaType.APPLICATION_JSON) + .content(json)) + .andDo(print()) + .andExpect(status().isOk()); + } } diff --git a/server/src/test/java/server/haengdong/presentation/admin/AdminEventControllerTest.java b/server/src/test/java/server/haengdong/presentation/admin/AdminEventControllerTest.java new file mode 100644 index 000000000..3ce2422c6 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/admin/AdminEventControllerTest.java @@ -0,0 +1,35 @@ +package server.haengdong.presentation.admin; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import server.haengdong.presentation.ControllerTestSupport; +import server.haengdong.presentation.request.MemberNameUpdateRequest; +import server.haengdong.presentation.request.MemberNamesUpdateRequest; + + +class AdminEventControllerTest extends ControllerTestSupport { + + @DisplayName("행사 참여 인원의 이름을 수정한다.") + @Test + void updateMember() throws Exception { + String token = "TOKEN"; + MemberNamesUpdateRequest memberNameUpdateRequest = new MemberNamesUpdateRequest(List.of( + new MemberNameUpdateRequest("토다링", "토쟁이"), + new MemberNameUpdateRequest("감자", "고구마") + )); + + String requestBody = objectMapper.writeValueAsString(memberNameUpdateRequest); + + mockMvc.perform(put("/api/admin/events/{eventId}/members/nameChange", token) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/admin/AdminMemberActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/admin/AdminMemberActionControllerTest.java new file mode 100644 index 000000000..e3d74640d --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/admin/AdminMemberActionControllerTest.java @@ -0,0 +1,53 @@ +package server.haengdong.presentation.admin; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import server.haengdong.presentation.ControllerTestSupport; +import server.haengdong.presentation.request.MemberActionsSaveRequest; + +class AdminMemberActionControllerTest extends ControllerTestSupport { + + @DisplayName("참여자 행동을 추가한다.") + @Test + void saveMemberActionTest() throws Exception { + MemberActionsSaveRequest memberActionsSaveRequest = new MemberActionsSaveRequest( + List.of("웨디", "소하", "토다리", "쿠키"), "IN"); + + String requestBody = objectMapper.writeValueAsString(memberActionsSaveRequest); + + mockMvc.perform(post("/api/admin/events/{eventId}/member-actions", "망쵸토큰") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") + @Test + void deleteMemberAction() throws Exception { + String eventId = "망쵸토큰"; + Long actionId = 2L; + + mockMvc.perform(delete("/api/admin/events/{eventId}/member-actions/{actionId}", eventId, actionId)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("행사의 전체 참여자 중에서 특정 참여자의 맴버 액션을 전부 삭제한다.") + @Test + void deleteMember() throws Exception { + String eventId = "망쵸토큰"; + String memberName = "행동대장"; + + mockMvc.perform(delete("/api/admin/events/{eventId}/members/{memberName}", eventId, memberName)) + .andDo(print()) + .andExpect(status().isOk()); + } +} From 8cd6fadb2f9bcb6adcc4f5c329dfea3312aa1be4 Mon Sep 17 00:00:00 2001 From: JUHA <84626225+khabh@users.noreply.github.com> Date: Mon, 9 Sep 2024 15:47:34 +0900 Subject: [PATCH 168/178] =?UTF-8?q?refactor:=20action=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EC=82=AD=EC=A0=9C=20(#542)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: action 도메인 삭제 Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: Arachneee <jhg2819@naver.com> Co-authored-by: kunsanglee <gosmdochee2@gmail.com> * refactor: 엔티티 not null, unique 설정 Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: Arachneee <jhg2819@naver.com> Co-authored-by: kunsanglee <gosmdochee2@gmail.com> --------- Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: Arachneee <jhg2819@naver.com> Co-authored-by: kunsanglee <gosmdochee2@gmail.com> --- .../haengdong/application/ActionService.java | 39 ------ .../application/BillActionDetailService.java | 14 +- .../application/BillActionService.java | 41 +++--- .../haengdong/application/EventService.java | 27 +++- .../application/MemberActionFactory.java | 14 +- .../application/MemberActionService.java | 36 ++--- .../request/BillActionAppRequest.java | 7 +- .../request/MemberActionSaveAppRequest.java | 7 +- .../response/ActionAppResponse.java | 8 +- .../haengdong/domain/action/Action.java | 42 ------ .../domain/action/ActionRepository.java | 23 ---- .../haengdong/domain/action/BillAction.java | 43 +++--- .../domain/action/BillActionDetail.java | 6 + .../action/BillActionDetailRepository.java | 2 +- .../domain/action/BillActionRepository.java | 20 +-- .../haengdong/domain/action/MemberAction.java | 38 +++--- .../domain/action/MemberActionRepository.java | 34 +++-- .../domain/action/MemberBillReport.java | 2 +- .../domain/action/MemberGroupIdProvider.java | 11 -- .../haengdong/domain/action/Sequence.java | 41 ++++++ .../server/haengdong/domain/event/Event.java | 4 +- .../haengdong/domain/event/EventStep.java | 28 ---- .../presentation/EventController.java | 4 +- .../application/ActionServiceTest.java | 91 ------------- .../BillActionDetailServiceTest.java | 20 +-- .../application/BillActionServiceTest.java | 58 ++++---- .../application/EventServiceTest.java | 124 ++++++++++++------ .../application/MemberActionFactoryTest.java | 81 ++++++------ .../application/MemberActionServiceTest.java | 82 +++++------- .../docs/EventControllerDocsTest.java | 6 +- .../haengdong/domain/action/ActionTest.java | 31 ----- .../domain/action/BillActionTest.java | 23 ++-- .../domain/action/CurrentMembersTest.java | 14 +- .../domain/action/MemberBillReportTest.java | 12 +- .../haengdong/domain/action/SequenceTest.java | 27 ++++ .../presentation/ControllerTestSupport.java | 4 - .../presentation/EventControllerTest.java | 2 +- .../haengdong/support/fixture/Fixture.java | 17 ++- 38 files changed, 482 insertions(+), 601 deletions(-) delete mode 100644 server/src/main/java/server/haengdong/application/ActionService.java delete mode 100644 server/src/main/java/server/haengdong/domain/action/Action.java delete mode 100644 server/src/main/java/server/haengdong/domain/action/ActionRepository.java delete mode 100644 server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java create mode 100644 server/src/main/java/server/haengdong/domain/action/Sequence.java delete mode 100644 server/src/main/java/server/haengdong/domain/event/EventStep.java delete mode 100644 server/src/test/java/server/haengdong/application/ActionServiceTest.java delete mode 100644 server/src/test/java/server/haengdong/domain/action/ActionTest.java create mode 100644 server/src/test/java/server/haengdong/domain/action/SequenceTest.java diff --git a/server/src/main/java/server/haengdong/application/ActionService.java b/server/src/main/java/server/haengdong/application/ActionService.java deleted file mode 100644 index bcf5e8b55..000000000 --- a/server/src/main/java/server/haengdong/application/ActionService.java +++ /dev/null @@ -1,39 +0,0 @@ -package server.haengdong.application; - -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import server.haengdong.application.response.MemberBillReportAppResponse; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.BillActionRepository; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionRepository; -import server.haengdong.domain.action.MemberBillReport; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -@RequiredArgsConstructor -@Transactional(readOnly = true) -@Service -public class ActionService { - - private final BillActionRepository billActionRepository; - private final MemberActionRepository memberActionRepository; - private final EventRepository eventRepository; - - public List<MemberBillReportAppResponse> getMemberBillReports(String token) { - Event event = eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); - List<BillAction> billActions = billActionRepository.findByAction_Event(event); - List<MemberAction> memberActions = memberActionRepository.findAllByEvent(event); - - MemberBillReport memberBillReport = MemberBillReport.createByActions(billActions, memberActions); - - return memberBillReport.getReports().entrySet().stream() - .map(entry -> new MemberBillReportAppResponse(entry.getKey(), entry.getValue())) - .toList(); - } -} diff --git a/server/src/main/java/server/haengdong/application/BillActionDetailService.java b/server/src/main/java/server/haengdong/application/BillActionDetailService.java index 55d39aac0..a4372c62d 100644 --- a/server/src/main/java/server/haengdong/application/BillActionDetailService.java +++ b/server/src/main/java/server/haengdong/application/BillActionDetailService.java @@ -21,8 +21,8 @@ public class BillActionDetailService { private final BillActionRepository billActionRepository; - public BillActionDetailsAppResponse findBillActionDetails(String token, Long actionId) { - BillAction billAction = billActionRepository.findByAction_Id(actionId) + public BillActionDetailsAppResponse findBillActionDetails(String token, Long billActionId) { + BillAction billAction = billActionRepository.findById(billActionId) .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); validateToken(token, billAction); @@ -31,8 +31,8 @@ public BillActionDetailsAppResponse findBillActionDetails(String token, Long act } @Transactional - public void updateBillActionDetails(String token, Long actionId, BillActionDetailsUpdateAppRequest request) { - BillAction billAction = billActionRepository.findByAction_Id(actionId) + public void updateBillActionDetails(String token, Long billActionId, BillActionDetailsUpdateAppRequest request) { + BillAction billAction = billActionRepository.findById(billActionId) .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); List<BillActionDetailUpdateAppRequest> billActionDetailUpdateAppRequests = request.billActionDetailUpdateAppRequests(); @@ -60,8 +60,10 @@ private void validateToken(String token, BillAction billAction) { } } - private void validateTotalPrice(List<BillActionDetailUpdateAppRequest> billActionDetailUpdateAppRequests, - BillAction billAction) { + private void validateTotalPrice( + List<BillActionDetailUpdateAppRequest> billActionDetailUpdateAppRequests, + BillAction billAction + ) { Long requestsPriceSum = calculateUpdatePriceSum(billActionDetailUpdateAppRequests); if (!billAction.isSamePrice(requestsPriceSum)) { throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_PRICE_NOT_MATCHED); diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java index dae36a2e7..9453a2d5f 100644 --- a/server/src/main/java/server/haengdong/application/BillActionService.java +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -6,13 +6,12 @@ import org.springframework.transaction.annotation.Transactional; import server.haengdong.application.request.BillActionAppRequest; import server.haengdong.application.request.BillActionUpdateAppRequest; -import server.haengdong.domain.action.Action; -import server.haengdong.domain.action.ActionRepository; import server.haengdong.domain.action.BillAction; import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.action.CurrentMembers; import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.action.Sequence; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.exception.HaengdongErrorCode; @@ -25,33 +24,35 @@ public class BillActionService { private final BillActionRepository billActionRepository; private final MemberActionRepository memberActionRepository; - private final ActionRepository actionRepository; private final EventRepository eventRepository; @Transactional public void saveAllBillAction(String eventToken, List<BillActionAppRequest> requests) { Event event = getEvent(eventToken); - Action action = createStartAction(event); + Sequence sequence = createStartSequence(event); List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event); CurrentMembers currentMembers = CurrentMembers.of(findMemberActions); for (BillActionAppRequest request : requests) { - BillAction billAction = request.toBillAction(action, currentMembers); + BillAction billAction = request.toBillAction(event, sequence, currentMembers); billActionRepository.save(billAction); - action = action.next(); + sequence = sequence.next(); } } - private Action createStartAction(Event event) { - return actionRepository.findLastByEvent(event) - .map(Action::next) - .orElse(Action.createFirst(event)); + private Sequence createStartSequence(Event event) { + Sequence memberActionSequence = memberActionRepository.findLastByEvent(event) + .map(MemberAction::getSequence) + .orElseGet(Sequence::createFirst); + Sequence billActionSequence = billActionRepository.findLastByEvent(event) + .map(BillAction::getSequence) + .orElseGet(Sequence::createFirst); + return Sequence.getGreater(memberActionSequence, billActionSequence).next(); } @Transactional - public void updateBillAction(String token, Long actionId, BillActionUpdateAppRequest request) { - BillAction billAction = billActionRepository.findByAction_Id(actionId) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); + public void updateBillAction(String token, Long billActionId, BillActionUpdateAppRequest request) { + BillAction billAction = getBillAction(billActionId); validateToken(token, billAction); @@ -66,15 +67,19 @@ private void validateToken(String token, BillAction billAction) { } @Transactional - public void deleteBillAction(String token, Long actionId) { - Event event = eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); - - billActionRepository.deleteByAction_EventAndActionId(event, actionId); + public void deleteBillAction(String token, Long billActionId) { + BillAction billAction = getBillAction(billActionId); + validateToken(token, billAction); + billActionRepository.deleteById(billActionId); } private Event getEvent(String eventToken) { return eventRepository.findByToken(eventToken) .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); } + + private BillAction getBillAction(Long billActionId) { + return billActionRepository.findById(billActionId) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); + } } diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java index 1aaddd0f9..106186af3 100644 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -14,12 +14,14 @@ import server.haengdong.application.response.ActionAppResponse; import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.application.response.MemberBillReportAppResponse; import server.haengdong.application.response.MembersAppResponse; import server.haengdong.domain.action.BillAction; import server.haengdong.domain.action.BillActionDetailRepository; import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.action.MemberBillReport; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.domain.event.EventTokenProvider; @@ -57,7 +59,7 @@ public EventDetailAppResponse findEvent(String token) { public List<ActionAppResponse> findActions(String token) { Event event = getEvent(token); - List<BillAction> billActions = billActionRepository.findByAction_Event(event).stream() + List<BillAction> billActions = billActionRepository.findByEvent(event).stream() .sorted(Comparator.comparing(BillAction::getSequence)).toList(); List<MemberAction> memberActions = memberActionRepository.findAllByEvent(event).stream() .sorted(Comparator.comparing(MemberAction::getSequence)).toList(); @@ -76,7 +78,7 @@ private List<ActionAppResponse> getActionAppResponses( while (billActionIndex < billActions.size() && memberActionIndex < memberActions.size()) { BillAction billAction = billActions.get(billActionIndex); MemberAction memberAction = memberActions.get(memberActionIndex); - if (billAction.getSequence() < memberAction.getSequence()) { + if (billAction.getSequence().getValue() < memberAction.getSequence().getValue()) { actionAppResponses.add(ActionAppResponse.of(billAction)); billActionIndex++; } else { @@ -126,7 +128,7 @@ private void validateBeforeNames(List<MemberNameUpdateAppRequest> members, Event } private void validateBeforeMemberNameExist(Event event, String beforeName) { - boolean isMemberNameExist = memberActionRepository.existsByAction_EventAndMemberName(event, beforeName); + boolean isMemberNameExist = memberActionRepository.existsByEventAndMemberName(event, beforeName); if (!isMemberNameExist) { throw new HaengdongException(HaengdongErrorCode.MEMBER_NOT_EXIST); } @@ -143,16 +145,16 @@ private void validateAfterNames(List<MemberNameUpdateAppRequest> members, Event } private void validateAfterMemberNameNotExist(Event event, String afterName) { - boolean isMemberNameExist = memberActionRepository.existsByAction_EventAndMemberName(event, afterName); + boolean isMemberNameExist = memberActionRepository.existsByEventAndMemberName(event, afterName); if (isMemberNameExist) { throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); } } private void updateMemberName(Event event, String beforeName, String afterName) { - memberActionRepository.findAllByAction_EventAndMemberName(event, beforeName) + memberActionRepository.findAllByEventAndMemberName(event, beforeName) .forEach(memberAction -> memberAction.updateMemberName(afterName)); - billActionDetailRepository.findAllByBillAction_Action_EventAndMemberName(event, beforeName) + billActionDetailRepository.findAllByBillAction_EventAndMemberName(event, beforeName) .forEach(billActionDetail -> billActionDetail.updateMemberName(afterName)); } @@ -167,4 +169,17 @@ private Event getEvent(String token) { return eventRepository.findByToken(token) .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); } + + public List<MemberBillReportAppResponse> getMemberBillReports(String token) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + List<BillAction> billActions = billActionRepository.findByEvent(event); + List<MemberAction> memberActions = memberActionRepository.findAllByEvent(event); + + MemberBillReport memberBillReport = MemberBillReport.createByActions(billActions, memberActions); + + return memberBillReport.getReports().entrySet().stream() + .map(entry -> new MemberBillReportAppResponse(entry.getKey(), entry.getValue())) + .toList(); + } } diff --git a/server/src/main/java/server/haengdong/application/MemberActionFactory.java b/server/src/main/java/server/haengdong/application/MemberActionFactory.java index c0a171642..97fa1038c 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionFactory.java +++ b/server/src/main/java/server/haengdong/application/MemberActionFactory.java @@ -6,11 +6,11 @@ import org.springframework.stereotype.Component; import server.haengdong.application.request.MemberActionSaveAppRequest; import server.haengdong.application.request.MemberActionsSaveAppRequest; -import server.haengdong.domain.action.Action; import server.haengdong.domain.action.CurrentMembers; import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionStatus; -import server.haengdong.domain.action.MemberGroupIdProvider; +import server.haengdong.domain.action.Sequence; +import server.haengdong.domain.event.Event; import server.haengdong.exception.HaengdongErrorCode; import server.haengdong.exception.HaengdongException; @@ -18,23 +18,21 @@ @Component public class MemberActionFactory { - private final MemberGroupIdProvider memberGroupIdProvider; - public List<MemberAction> createMemberActions( + Event event, MemberActionsSaveAppRequest request, CurrentMembers currentMembers, - Action action + Sequence sequence ) { validateMemberNames(request); validateActions(request, currentMembers); - Long memberGroupId = memberGroupIdProvider.createGroupId(); List<MemberAction> createdMemberActions = new ArrayList<>(); List<MemberActionSaveAppRequest> actions = request.actions(); for (MemberActionSaveAppRequest appRequest : actions) { - MemberAction memberAction = appRequest.toMemberAction(action, memberGroupId); + MemberAction memberAction = appRequest.toMemberAction(event, sequence); createdMemberActions.add(memberAction); - action = action.next(); + sequence = sequence.next(); } return createdMemberActions; diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java index 245de8cef..26186c08a 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionService.java +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -6,13 +6,12 @@ import org.springframework.transaction.annotation.Transactional; import server.haengdong.application.request.MemberActionsSaveAppRequest; import server.haengdong.application.response.CurrentMemberAppResponse; -import server.haengdong.domain.action.Action; -import server.haengdong.domain.action.ActionRepository; import server.haengdong.domain.action.BillAction; import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.action.CurrentMembers; import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.action.Sequence; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.exception.HaengdongErrorCode; @@ -26,7 +25,6 @@ public class MemberActionService { private final MemberActionFactory memberActionFactory; private final MemberActionRepository memberActionRepository; private final EventRepository eventRepository; - private final ActionRepository actionRepository; private final BillActionRepository billActionRepository; @Transactional @@ -35,15 +33,20 @@ public void saveMemberAction(String token, MemberActionsSaveAppRequest request) List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event); CurrentMembers currentMembers = CurrentMembers.of(findMemberActions); - Action action = createStartAction(event); - List<MemberAction> memberActions = memberActionFactory.createMemberActions(request, currentMembers, action); + Sequence sequence = createStartSequence(event); + List<MemberAction> memberActions = memberActionFactory.createMemberActions(event, request, currentMembers, + sequence); memberActionRepository.saveAll(memberActions); } - private Action createStartAction(Event event) { - return actionRepository.findLastByEvent(event) - .map(Action::next) - .orElse(Action.createFirst(event)); + private Sequence createStartSequence(Event event) { + Sequence memberActionSequence = memberActionRepository.findLastByEvent(event) + .map(MemberAction::getSequence) + .orElseGet(Sequence::createFirst); + Sequence billActionSequence = billActionRepository.findLastByEvent(event) + .map(BillAction::getSequence) + .orElseGet(Sequence::createFirst); + return Sequence.getGreater(memberActionSequence, billActionSequence).next(); } public List<CurrentMemberAppResponse> getCurrentMembers(String token) { @@ -69,30 +72,27 @@ public void deleteMember(String token, String memberName) { memberActionRepository.deleteAllByEventAndMemberName(event, memberName); - List<BillAction> billActions = billActionRepository.findByAction_Event(event); + List<BillAction> billActions = billActionRepository.findByEvent(event); billActions.forEach(billAction -> resetBillAction(event, billAction)); } @Transactional - public void deleteMemberAction(String token, Long actionId) { + public void deleteMemberAction(String token, Long id) { Event event = eventRepository.findByToken(token) .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); - Action action = actionRepository.findByIdAndEvent(actionId, event) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.ACTION_NOT_FOUND)); - MemberAction memberAction = memberActionRepository.findByAction(action) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_ACTION_NOT_FOUND)); + MemberAction memberAction = memberActionRepository.findByIdAndEvent(id, event); memberActionRepository.deleteAllByMemberNameAndMinSequence(memberAction.getMemberName(), - memberAction.getSequence()); + memberAction.getSequence().getValue()); List<BillAction> billActions = billActionRepository.findByEventAndGreaterThanSequence(event, - action.getSequence()); + memberAction.getSequence().getValue()); billActions.forEach(billAction -> resetBillAction(event, billAction)); } private void resetBillAction(Event event, BillAction billAction) { List<MemberAction> memberActions = memberActionRepository.findByEventAndSequence(event, - billAction.getSequence()); + billAction.getSequence().getValue()); CurrentMembers currentMembers = CurrentMembers.of(memberActions); billAction.resetBillActionDetails(currentMembers); diff --git a/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java index 21eb17d4a..c702fd0be 100644 --- a/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java +++ b/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java @@ -1,15 +1,16 @@ package server.haengdong.application.request; -import server.haengdong.domain.action.Action; import server.haengdong.domain.action.BillAction; import server.haengdong.domain.action.CurrentMembers; +import server.haengdong.domain.action.Sequence; +import server.haengdong.domain.event.Event; public record BillActionAppRequest( String title, Long price ) { - public BillAction toBillAction(Action action, CurrentMembers currentMembers) { - return BillAction.create(action, title, price, currentMembers); + public BillAction toBillAction(Event event, Sequence sequence, CurrentMembers currentMembers) { + return BillAction.create(event, sequence, title, price, currentMembers); } } diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java index f7f8d8fc2..f56b89517 100644 --- a/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java +++ b/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java @@ -1,12 +1,13 @@ package server.haengdong.application.request; -import server.haengdong.domain.action.Action; import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionStatus; +import server.haengdong.domain.action.Sequence; +import server.haengdong.domain.event.Event; public record MemberActionSaveAppRequest(String name, String status) { - public MemberAction toMemberAction(Action action, Long memberGroupId) { - return new MemberAction(action, name, MemberActionStatus.of(status), memberGroupId); + public MemberAction toMemberAction(Event event, Sequence sequence) { + return new MemberAction(event, sequence, name, MemberActionStatus.of(status)); } } diff --git a/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java b/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java index 0c2c12611..931a5c6ba 100644 --- a/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java +++ b/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java @@ -19,10 +19,10 @@ public ActionAppResponse(Long actionId, String name, Long price, Long sequence, public static ActionAppResponse of(BillAction billAction) { return new ActionAppResponse( - billAction.getAction().getId(), + billAction.getId(), billAction.getTitle(), billAction.getPrice(), - billAction.getSequence(), + billAction.getSequence().getValue(), billAction.isFixed(), ActionAppResponse.ActionType.BILL ); @@ -32,10 +32,10 @@ public static ActionAppResponse of(MemberAction memberAction) { MemberActionStatus status = memberAction.getStatus(); return new ActionAppResponse( - memberAction.getAction().getId(), + memberAction.getId(), memberAction.getMemberName(), null, - memberAction.getSequence(), + memberAction.getSequence().getValue(), false, ActionAppResponse.ActionType.of(status) ); diff --git a/server/src/main/java/server/haengdong/domain/action/Action.java b/server/src/main/java/server/haengdong/domain/action/Action.java deleted file mode 100644 index 11f91fc38..000000000 --- a/server/src/main/java/server/haengdong/domain/action/Action.java +++ /dev/null @@ -1,42 +0,0 @@ -package server.haengdong.domain.action; - -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.ManyToOne; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import server.haengdong.domain.event.Event; - -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@Entity -public class Action { - - private static final long FIRST_SEQUENCE = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @ManyToOne(fetch = FetchType.LAZY) - private Event event; - - private Long sequence; - - public Action(Event event, Long sequence) { - this.event = event; - this.sequence = sequence; - } - - public static Action createFirst(Event event) { - return new Action(event, FIRST_SEQUENCE); - } - - public Action next() { - return new Action(event, sequence + 1); - } -} diff --git a/server/src/main/java/server/haengdong/domain/action/ActionRepository.java b/server/src/main/java/server/haengdong/domain/action/ActionRepository.java deleted file mode 100644 index 2fde0ffa6..000000000 --- a/server/src/main/java/server/haengdong/domain/action/ActionRepository.java +++ /dev/null @@ -1,23 +0,0 @@ -package server.haengdong.domain.action; - -import java.util.Optional; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; -import server.haengdong.domain.event.Event; - -@Repository -public interface ActionRepository extends JpaRepository<Action, Long> { - - @Query(""" - SELECT a - FROM Action a - WHERE a.event = :event - ORDER BY a.sequence DESC - LIMIT 1 - """) - Optional<Action> findLastByEvent(@Param("event") Event event); - - Optional<Action> findByIdAndEvent(Long id, Event event); -} diff --git a/server/src/main/java/server/haengdong/domain/action/BillAction.java b/server/src/main/java/server/haengdong/domain/action/BillAction.java index 943b40ce5..56ca8c20e 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillAction.java +++ b/server/src/main/java/server/haengdong/domain/action/BillAction.java @@ -1,14 +1,19 @@ package server.haengdong.domain.action; +import jakarta.persistence.AttributeOverride; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; +import jakarta.persistence.Embedded; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; -import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -23,6 +28,7 @@ @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"event_id", "sequence"})}) @Entity public class BillAction implements Comparable<BillAction> { @@ -36,21 +42,28 @@ public class BillAction implements Comparable<BillAction> { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) - private Action action; + @JoinColumn(name = "event_id", nullable = false) + @ManyToOne(fetch = FetchType.LAZY) + private Event event; - @Column(length = MAX_TITLE_LENGTH) + @AttributeOverride(name = "value", column = @Column(name = "sequence", nullable = false)) + @Embedded + private Sequence sequence; + + @Column(nullable = false, length = MAX_TITLE_LENGTH) private String title; + @Column(nullable = false) private Long price; @OneToMany(mappedBy = "billAction", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) private List<BillActionDetail> billActionDetails = new ArrayList<>(); - public BillAction(Action action, String title, Long price) { + public BillAction(Event event, Sequence sequence, String title, Long price) { validateTitle(title); validatePrice(price); - this.action = action; + this.event = event; + this.sequence = sequence; this.title = title.trim(); this.price = price; } @@ -68,8 +81,10 @@ private void validatePrice(Long price) { } } - public static BillAction create(Action action, String title, Long price, CurrentMembers currentMembers) { - BillAction billAction = new BillAction(action, title, price); + public static BillAction create( + Event event, Sequence sequence, String title, Long price, CurrentMembers currentMembers + ) { + BillAction billAction = new BillAction(event, sequence, title, price); billAction.resetBillActionDetails(currentMembers); return billAction; } @@ -138,19 +153,11 @@ public Long findPriceByMemberName(String memberName) { .filter(billActionDetail -> billActionDetail.hasMemberName(memberName)) .map(BillActionDetail::getPrice) .findFirst() - .orElse(DEFAULT_PRICE); - } - - public Long getSequence() { - return action.getSequence(); - } - - public Event getEvent() { - return action.getEvent(); + .orElseGet(() -> DEFAULT_PRICE); } @Override public int compareTo(BillAction o) { - return Long.compare(this.getSequence(), o.getSequence()); + return sequence.compareTo(o.sequence); } } diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java index ffdfe04a3..09776e0d3 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java @@ -1,10 +1,12 @@ package server.haengdong.domain.action; +import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import lombok.AccessLevel; import lombok.Getter; @@ -19,13 +21,17 @@ public class BillActionDetail { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @JoinColumn(nullable = false) @ManyToOne(fetch = FetchType.LAZY) private BillAction billAction; + @Column(nullable = false) private String memberName; + @Column(nullable = false) private Long price; + @Column(nullable = false) private boolean isFixed; public BillActionDetail(BillAction billAction, String memberName, Long price, boolean isFixed) { diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java index 05de55304..47d5d83e5 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java @@ -16,5 +16,5 @@ public interface BillActionDetailRepository extends JpaRepository<BillActionDeta """) List<BillActionDetail> findAllByBillAction(BillAction billAction); - List<BillActionDetail> findAllByBillAction_Action_EventAndMemberName(Event event, String memberName); + List<BillActionDetail> findAllByBillAction_EventAndMemberName(Event event, String memberName); } diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java index 817a63bf8..d05451882 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java @@ -2,26 +2,30 @@ import java.util.List; import java.util.Optional; -import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import server.haengdong.domain.event.Event; @Repository public interface BillActionRepository extends JpaRepository<BillAction, Long> { - @EntityGraph(attributePaths = {"action"}) - List<BillAction> findByAction_Event(Event event); - - void deleteByAction_EventAndActionId(Event event, Long actionId); - - Optional<BillAction> findByAction_Id(Long actionId); + List<BillAction> findByEvent(Event event); @Query(""" select ba from BillAction ba - where ba.action.event = :event and ba.action.sequence > :sequence + where ba.event = :event and ba.sequence.value > :sequence """) List<BillAction> findByEventAndGreaterThanSequence(Event event, Long sequence); + + @Query(""" + select ba + from BillAction ba + WHERE ba.event = :event + ORDER BY ba.sequence DESC + LIMIT 1 + """) + Optional<BillAction> findLastByEvent(@Param("event") Event event); } diff --git a/server/src/main/java/server/haengdong/domain/action/MemberAction.java b/server/src/main/java/server/haengdong/domain/action/MemberAction.java index 3faf65bde..18efc1611 100644 --- a/server/src/main/java/server/haengdong/domain/action/MemberAction.java +++ b/server/src/main/java/server/haengdong/domain/action/MemberAction.java @@ -1,6 +1,8 @@ package server.haengdong.domain.action; -import jakarta.persistence.CascadeType; +import jakarta.persistence.AttributeOverride; +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; @@ -8,41 +10,51 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import jakarta.persistence.OneToOne; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; +import server.haengdong.domain.event.Event; import server.haengdong.exception.HaengdongErrorCode; import server.haengdong.exception.HaengdongException; @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"event_id", "sequence"})}) @Entity public class MemberAction implements Comparable<MemberAction> { public static final int MIN_NAME_LENGTH = 1; - public static final int MAX_NAME_LENGTH = 4; + public static final int MAX_NAME_LENGTH = 8; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) - private Action action; + @JoinColumn(name = "event_id", nullable = false) + @ManyToOne(fetch = FetchType.LAZY) + private Event event; + @AttributeOverride(name = "value", column = @Column(name = "sequence", nullable = false)) + @Embedded + private Sequence sequence; + + @Column(nullable = false, length = MAX_NAME_LENGTH) private String memberName; + @Column(nullable = false) @Enumerated(EnumType.STRING) private MemberActionStatus status; - private Long memberGroupId; - - public MemberAction(Action action, String memberName, MemberActionStatus status, Long memberGroupId) { + public MemberAction(Event event, Sequence sequence, String memberName, MemberActionStatus status) { validateMemberName(memberName); - this.action = action; + this.event = event; + this.sequence = sequence; this.memberName = memberName; this.status = status; - this.memberGroupId = memberGroupId; } private void validateMemberName(String memberName) { @@ -65,12 +77,8 @@ public boolean isSameStatus(MemberActionStatus memberActionStatus) { return status == memberActionStatus; } - public Long getSequence() { - return action.getSequence(); - } - @Override public int compareTo(MemberAction o) { - return Long.compare(this.getSequence(), o.getSequence()); + return sequence.compareTo(o.sequence); } } diff --git a/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java index 324ff9797..9aceed477 100644 --- a/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java @@ -12,42 +12,50 @@ @Repository public interface MemberActionRepository extends JpaRepository<MemberAction, Long> { - @Query("select m from MemberAction m join fetch m.action where m.action.event = :event") List<MemberAction> findAllByEvent(@Param("event") Event event); @Query(""" - select distinct m.memberName - from MemberAction m - where m.action.event = :event + select distinct ma.memberName + from MemberAction ma + where ma.event = :event """) List<String> findAllUniqueMemberByEvent(Event event); @Modifying @Query(""" delete - from MemberAction m - where m.memberName = :memberName and m.action.event = :event + from MemberAction ma + where ma.memberName = :memberName and ma.event = :event """) void deleteAllByEventAndMemberName(Event event, String memberName); - Optional<MemberAction> findByAction(Action action); - @Modifying @Query(""" delete - from MemberAction m - where m.memberName = :memberName and m.action.sequence >= :sequence + from MemberAction ma + where ma.memberName = :memberName and ma.sequence.value >= :sequence """) void deleteAllByMemberNameAndMinSequence(String memberName, Long sequence); - List<MemberAction> findAllByAction_EventAndMemberName(Event event, String memberName); + List<MemberAction> findAllByEventAndMemberName(Event event, String memberName); - boolean existsByAction_EventAndMemberName(Event event, String updatedMemberName); + boolean existsByEventAndMemberName(Event event, String updatedMemberName); @Query(""" select ma from MemberAction ma - where ma.action.event = :event and ma.action.sequence < :sequence + where ma.event = :event and ma.sequence.value < :sequence """) List<MemberAction> findByEventAndSequence(Event event, Long sequence); + + @Query(""" + select ma + from MemberAction ma + WHERE ma.event = :event + ORDER BY ma.sequence.value DESC + LIMIT 1 + """) + Optional<MemberAction> findLastByEvent(@Param("event") Event event); + + MemberAction findByIdAndEvent(Long actionId, Event event); } diff --git a/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java b/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java index 7a707b9d8..5fcb6ebd3 100644 --- a/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java +++ b/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java @@ -53,7 +53,7 @@ private static boolean isMemberActionTurn( MemberAction memberAction = memberActions.peek(); BillAction billAction = billActions.peek(); - return memberAction.getSequence() < billAction.getSequence(); + return memberAction.getSequence().getValue() < billAction.getSequence().getValue(); } private static void addBillAction( diff --git a/server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java b/server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java deleted file mode 100644 index 9e32bd733..000000000 --- a/server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java +++ /dev/null @@ -1,11 +0,0 @@ -package server.haengdong.domain.action; - -import org.springframework.stereotype.Component; - -@Component -public class MemberGroupIdProvider { - - public Long createGroupId() { - return System.currentTimeMillis(); - } -} diff --git a/server/src/main/java/server/haengdong/domain/action/Sequence.java b/server/src/main/java/server/haengdong/domain/action/Sequence.java new file mode 100644 index 000000000..39a99d063 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/Sequence.java @@ -0,0 +1,41 @@ +package server.haengdong.domain.action; + +import jakarta.persistence.Embeddable; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@EqualsAndHashCode +@Getter +@NoArgsConstructor +@Embeddable +public class Sequence implements Comparable<Sequence> { + + private static final long FIRST_SEQUENCE = 1L; + + private Long value; + + public Sequence(Long value) { + this.value = value; + } + + public static Sequence createFirst() { + return new Sequence(FIRST_SEQUENCE); + } + + public static Sequence getGreater(Sequence first, Sequence second) { + if (first.compareTo(second) > 0) { + return first; + } + return second; + } + + public Sequence next() { + return new Sequence(value + 1); + } + + @Override + public int compareTo(Sequence o) { + return Long.compare(value, o.value); + } +} diff --git a/server/src/main/java/server/haengdong/domain/event/Event.java b/server/src/main/java/server/haengdong/domain/event/Event.java index bb5d53dbc..be8874414 100644 --- a/server/src/main/java/server/haengdong/domain/event/Event.java +++ b/server/src/main/java/server/haengdong/domain/event/Event.java @@ -26,12 +26,14 @@ public class Event { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Column(nullable = false, length = MAX_NAME_LENGTH) private String name; @Embedded - @AttributeOverride(name = "value", column = @Column(name = "password")) + @AttributeOverride(name = "value", column = @Column(name = "password", nullable = false)) private Password password; + @Column(nullable = false, unique = true) private String token; public Event(String name, String password, String token) { diff --git a/server/src/main/java/server/haengdong/domain/event/EventStep.java b/server/src/main/java/server/haengdong/domain/event/EventStep.java deleted file mode 100644 index 297abdb66..000000000 --- a/server/src/main/java/server/haengdong/domain/event/EventStep.java +++ /dev/null @@ -1,28 +0,0 @@ -package server.haengdong.domain.event; - -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.ManyToOne; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@Entity -public class EventStep { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @ManyToOne(fetch = FetchType.LAZY) - private Event event; - - private String name; - - private Long sequence; -} diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java index 57d0515e7..af725864d 100644 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -13,7 +13,6 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import server.haengdong.application.ActionService; import server.haengdong.application.AuthService; import server.haengdong.application.EventService; import server.haengdong.application.response.ActionAppResponse; @@ -37,7 +36,6 @@ public class EventController { private final EventService eventService; private final AuthService authService; private final CookieProperties cookieProperties; - private final ActionService actionService; @GetMapping("/api/events/{eventId}") public ResponseEntity<EventDetailResponse> findEvent(@PathVariable("eventId") String token) { @@ -70,7 +68,7 @@ public ResponseEntity<MembersResponse> findAllMembers(@PathVariable("eventId") S @GetMapping("/api/events/{eventId}/reports") public ResponseEntity<MemberBillReportsResponse> getMemberBillReports(@PathVariable("eventId") String token) { - List<MemberBillReportAppResponse> memberBillReports = actionService.getMemberBillReports(token); + List<MemberBillReportAppResponse> memberBillReports = eventService.getMemberBillReports(token); return ResponseEntity.ok() .body(MemberBillReportsResponse.of(memberBillReports)); diff --git a/server/src/test/java/server/haengdong/application/ActionServiceTest.java b/server/src/test/java/server/haengdong/application/ActionServiceTest.java deleted file mode 100644 index ee979b278..000000000 --- a/server/src/test/java/server/haengdong/application/ActionServiceTest.java +++ /dev/null @@ -1,91 +0,0 @@ -package server.haengdong.application; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.assertj.core.api.Assertions.tuple; -import static server.haengdong.domain.action.MemberActionStatus.IN; -import static server.haengdong.domain.action.MemberActionStatus.OUT; -import static server.haengdong.support.fixture.Fixture.BILL_ACTION; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import server.haengdong.application.response.MemberBillReportAppResponse; -import server.haengdong.domain.action.Action; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.BillActionDetail; -import server.haengdong.domain.action.BillActionRepository; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionRepository; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; -import server.haengdong.support.fixture.Fixture; - -class ActionServiceTest extends ServiceTestSupport { - - @Autowired - private ActionService actionService; - - @Autowired - private EventRepository eventRepository; - - @Autowired - private BillActionRepository billActionRepository; - - @Autowired - private MemberActionRepository memberActionRepository; - - @DisplayName("참여자별 정산 현황을 조회한다.") - @Test - void getMemberBillReports() { - Event event = Fixture.EVENT1; - Event savedEvent = eventRepository.save(event); - List<MemberAction> memberActions = List.of( - new MemberAction(new Action(savedEvent, 1L), "소하", IN, 1L), - new MemberAction(new Action(savedEvent, 2L), "감자", IN, 1L), - new MemberAction(new Action(savedEvent, 3L), "쿠키", IN, 1L), - new MemberAction(new Action(savedEvent, 5L), "감자", OUT, 2L) - ); - List<BillAction> billActions = List.of( - new BillAction(new Action(savedEvent, 4L), "뽕족", 60_000L), - new BillAction(new Action(savedEvent, 7L), "인생네컷", 20_000L) - ); - billActions.get(0).addDetails( - List.of( - new BillActionDetail(BILL_ACTION, "소하", 10_000L, false), - new BillActionDetail(BILL_ACTION, "감자", 40_000L, true), - new BillActionDetail(BILL_ACTION, "쿠키", 10_000L, false) - ) - ); - billActions.get(1).addDetails( - List.of( - new BillActionDetail(BILL_ACTION, "소하", 5_000L, true), - new BillActionDetail(BILL_ACTION, "쿠키", 15_000L, true) - ) - ); - memberActionRepository.saveAll(memberActions); - billActionRepository.saveAll(billActions); - - List<MemberBillReportAppResponse> responses = actionService.getMemberBillReports(event.getToken()); - - assertThat(responses) - .hasSize(3) - .extracting(MemberBillReportAppResponse::name, MemberBillReportAppResponse::price) - .containsExactlyInAnyOrder( - tuple("감자", 40_000L), - tuple("쿠키", 25_000L), - tuple("소하", 15_000L) - ); - } - - @DisplayName("존재하지 않는 이벤트의 참여자별 정산 현황을 조회하는 경우 예외가 발생한다.") - @Test - void getMemberBillReports1() { - assertThatThrownBy(() -> actionService.getMemberBillReports("invalid token")) - .isInstanceOf(HaengdongException.class) - .hasMessage(HaengdongErrorCode.EVENT_NOT_FOUND.getMessage()); - } -} diff --git a/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java index 7074ce846..c89d057eb 100644 --- a/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java +++ b/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java @@ -12,11 +12,11 @@ import server.haengdong.application.request.BillActionDetailsUpdateAppRequest; import server.haengdong.application.response.BillActionDetailAppResponse; import server.haengdong.application.response.BillActionDetailsAppResponse; -import server.haengdong.domain.action.Action; import server.haengdong.domain.action.BillAction; import server.haengdong.domain.action.BillActionDetail; import server.haengdong.domain.action.BillActionDetailRepository; import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.Sequence; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.exception.HaengdongException; @@ -41,15 +41,15 @@ class BillActionDetailServiceTest extends ServiceTestSupport { void findBillActionDetailsTest() { Event event1 = Fixture.EVENT1; eventRepository.save(event1); - Action action = new Action(event1, 1L); - BillAction billAction = new BillAction(action, "뽕족", 10000L); + Sequence sequence = Sequence.createFirst(); + BillAction billAction = new BillAction(event1, sequence, "뽕족", 10000L); billActionRepository.save(billAction); BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "토다리", 6000L, true); BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "쿠키", 4000L, true); billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); BillActionDetailsAppResponse response = billActionDetailService.findBillActionDetails( - event1.getToken(), action.getId()); + event1.getToken(), billAction.getId()); assertThat(response.billActionDetailAppResponses()).hasSize(2) .extracting(BillActionDetailAppResponse::name, BillActionDetailAppResponse::price) @@ -64,8 +64,8 @@ void findBillActionDetailsTest() { void updateBillActionDetailsTest1() { Event event1 = Fixture.EVENT1; eventRepository.save(event1); - Action action = new Action(event1, 1L); - BillAction billAction = new BillAction(action, "뽕족", 10000L); + Sequence sequence = Sequence.createFirst(); + BillAction billAction = new BillAction(event1, sequence, "뽕족", 10000L); billActionRepository.save(billAction); BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "토다리", 5000L, false); BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "쿠키", 5000L, false); @@ -76,7 +76,7 @@ void updateBillActionDetailsTest1() { new BillActionDetailUpdateAppRequest("쿠키", 4000L, true) )); assertThatCode( - () -> billActionDetailService.updateBillActionDetails(event1.getToken(), action.getId(), request)) + () -> billActionDetailService.updateBillActionDetails(event1.getToken(), billAction.getId(), request)) .isInstanceOf(HaengdongException.class) .hasMessage("지출 총액이 일치하지 않습니다."); } @@ -86,8 +86,8 @@ void updateBillActionDetailsTest1() { void updateBillActionDetailsTest2() { Event event1 = Fixture.EVENT1; eventRepository.save(event1); - Action action = new Action(event1, 1L); - BillAction billAction = new BillAction(action, "뽕족", 10000L); + Sequence sequence = Sequence.createFirst(); + BillAction billAction = new BillAction(event1, sequence, "뽕족", 10000L); billActionRepository.save(billAction); BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "토다리", 5000L, false); BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "쿠키", 5000L, false); @@ -97,7 +97,7 @@ void updateBillActionDetailsTest2() { new BillActionDetailUpdateAppRequest("토다리", 3000L, true), new BillActionDetailUpdateAppRequest("쿠키", 7000L, true) )); - billActionDetailService.updateBillActionDetails(event1.getToken(), action.getId(), request); + billActionDetailService.updateBillActionDetails(event1.getToken(), billAction.getId(), request); List<BillActionDetail> results = billActionDetailRepository.findAll(); diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java index 39e52f80c..30675acdd 100644 --- a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java @@ -11,7 +11,6 @@ import org.springframework.beans.factory.annotation.Autowired; import server.haengdong.application.request.BillActionAppRequest; import server.haengdong.application.request.BillActionUpdateAppRequest; -import server.haengdong.domain.action.Action; import server.haengdong.domain.action.BillAction; import server.haengdong.domain.action.BillActionDetail; import server.haengdong.domain.action.BillActionDetailRepository; @@ -19,6 +18,7 @@ import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionRepository; import server.haengdong.domain.action.MemberActionStatus; +import server.haengdong.domain.action.Sequence; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.exception.HaengdongException; @@ -46,10 +46,10 @@ class BillActionServiceTest extends ServiceTestSupport { void saveAllBillAction() { Event event = Fixture.EVENT1; Event savedEvent = eventRepository.save(event); - Action action1 = new Action(event, 1L); - Action action2 = new Action(event, 2L); - MemberAction memberAction1 = new MemberAction(action1, "백호", MemberActionStatus.IN, 1L); - MemberAction memberAction2 = new MemberAction(action2, "망쵸", MemberActionStatus.IN, 2L); + Sequence sequence1 = Sequence.createFirst(); + Sequence sequence2 = sequence1.next(); + MemberAction memberAction1 = new MemberAction(event, sequence1, "백호", MemberActionStatus.IN); + MemberAction memberAction2 = new MemberAction(event, sequence2, "망쵸", MemberActionStatus.IN); memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); List<BillActionAppRequest> requests = List.of( @@ -59,12 +59,12 @@ void saveAllBillAction() { billActionService.saveAllBillAction(event.getToken(), requests); - List<BillAction> actions = billActionRepository.findByAction_Event(savedEvent); + List<BillAction> actions = billActionRepository.findByEvent(savedEvent); assertThat(actions).extracting(BillAction::getTitle, BillAction::getPrice, BillAction::getSequence) .containsExactlyInAnyOrder( - tuple("뽕족", 10_000L, 3L), - tuple("인생맥주", 15_000L, 4L) + tuple("뽕족", 10_000L, new Sequence(3L)), + tuple("인생맥주", 15_000L, new Sequence(4L)) ); } @@ -73,10 +73,10 @@ void saveAllBillAction() { void saveAllBillActionTest1() { Event event = Fixture.EVENT1; Event savedEvent = eventRepository.save(event); - Action action1 = new Action(event, 1L); - Action action2 = new Action(event, 2L); - MemberAction memberAction1 = new MemberAction(action1, "백호", MemberActionStatus.IN, 1L); - MemberAction memberAction2 = new MemberAction(action2, "망쵸", MemberActionStatus.IN, 2L); + Sequence sequence1 = Sequence.createFirst(); + Sequence sequence2 = sequence1.next(); + MemberAction memberAction1 = new MemberAction(event, sequence1, "백호", MemberActionStatus.IN); + MemberAction memberAction2 = new MemberAction(event, sequence2, "망쵸", MemberActionStatus.IN); memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); List<BillActionAppRequest> request = List.of( @@ -116,11 +116,11 @@ void saveAllBillAction1() { void updateBillAction() { Event event = Fixture.EVENT1; Event savedEvent = eventRepository.save(event); - Action action = Action.createFirst(savedEvent); - BillAction billAction = new BillAction(action, "뽕족", 10_000L); + Sequence sequence = Sequence.createFirst(); + BillAction billAction = new BillAction(event, sequence, "뽕족", 10_000L); BillAction savedBillAction = billActionRepository.save(billAction); - Long actionId = savedBillAction.getAction().getId(); + Long actionId = savedBillAction.getId(); BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L); billActionService.updateBillAction(event.getToken(), actionId, request); @@ -140,14 +140,14 @@ void updateBillAction1() { Event event2 = Fixture.EVENT2; Event savedEvent1 = eventRepository.save(event1); Event savedEvent2 = eventRepository.save(event2); - Action action1 = Action.createFirst(savedEvent1); - Action action2 = Action.createFirst(savedEvent2); - BillAction billAction1 = new BillAction(action1, "뽕족", 10_000L); - BillAction billAction2 = new BillAction(action2, "뽕족", 10_000L); + Sequence sequence1 = Sequence.createFirst(); + Sequence sequence2 = Sequence.createFirst(); + BillAction billAction1 = new BillAction(event1, sequence1, "뽕족", 10_000L); + BillAction billAction2 = new BillAction(event2, sequence2, "뽕족", 10_000L); BillAction savedBillAction1 = billActionRepository.save(billAction1); billActionRepository.save(billAction2); - Long actionId = savedBillAction1.getAction().getId(); + Long actionId = savedBillAction1.getId(); BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L); assertThatThrownBy(() -> billActionService.updateBillAction(event2.getToken(), actionId, request)) @@ -159,8 +159,8 @@ void updateBillAction1() { void updateBillAction2() { Event event = Fixture.EVENT1; Event savedEvent = eventRepository.save(event); - Action action = Action.createFirst(savedEvent); - BillAction billAction = new BillAction(action, "뽕족", 10_000L); + Sequence sequence = Sequence.createFirst(); + BillAction billAction = new BillAction(event, sequence, "뽕족", 10_000L); BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "감자", 3000L, true); BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "고구마", 2000L, true); BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "당근", 3000L, true); @@ -168,7 +168,7 @@ void updateBillAction2() { billAction.addDetails(List.of(billActionDetail1, billActionDetail2, billActionDetail3, billActionDetail4)); BillAction savedBillAction = billActionRepository.save(billAction); - Long actionId = savedBillAction.getAction().getId(); + Long actionId = savedBillAction.getId(); BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L); billActionService.updateBillAction(event.getToken(), actionId, request); @@ -191,9 +191,9 @@ void updateBillAction2() { void deleteBillAction() { Event event = Fixture.EVENT1; eventRepository.save(event); - BillAction billAction = new BillAction(new Action(event, 1L), "커피", 50_900L); + BillAction billAction = Fixture.createBillAction(event, 1L, "커피", 50_900L); billActionRepository.save(billAction); - Long actionId = billAction.getAction().getId(); + Long actionId = billAction.getId(); billActionService.deleteBillAction(event.getToken(), actionId); @@ -205,15 +205,15 @@ void deleteBillAction() { void deleteBillActionTest1() { Event event = Fixture.EVENT1; eventRepository.save(event); - MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "백호", MemberActionStatus.IN, 1L); - MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "망쵸", MemberActionStatus.IN, 2L); - BillAction billAction = new BillAction(new Action(event, 3L), "커피", 50_900L); + MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "백호", MemberActionStatus.IN); + MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "망쵸", MemberActionStatus.IN); + BillAction billAction = Fixture.createBillAction(event, 3L, "커피", 50_900L); BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "백호", 25_450L, false); BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "망쵸", 25_450L, false); memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); billActionRepository.save(billAction); billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); - Long actionId = billAction.getAction().getId(); + Long actionId = billAction.getId(); billActionService.deleteBillAction(event.getToken(), actionId); diff --git a/server/src/test/java/server/haengdong/application/EventServiceTest.java b/server/src/test/java/server/haengdong/application/EventServiceTest.java index 407fa1457..37e6372a8 100644 --- a/server/src/test/java/server/haengdong/application/EventServiceTest.java +++ b/server/src/test/java/server/haengdong/application/EventServiceTest.java @@ -7,6 +7,7 @@ import static org.mockito.BDDMockito.given; import static server.haengdong.domain.action.MemberActionStatus.IN; import static server.haengdong.domain.action.MemberActionStatus.OUT; +import static server.haengdong.support.fixture.Fixture.BILL_ACTION; import java.util.List; import org.junit.jupiter.api.DisplayName; @@ -19,15 +20,18 @@ import server.haengdong.application.response.ActionAppResponse; import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.application.response.MemberBillReportAppResponse; import server.haengdong.application.response.MembersAppResponse; -import server.haengdong.domain.action.Action; import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.action.Sequence; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.domain.event.EventTokenProvider; +import server.haengdong.exception.HaengdongErrorCode; import server.haengdong.exception.HaengdongException; import server.haengdong.support.fixture.Fixture; @@ -74,12 +78,9 @@ void findEventTest() { @Test void findActionsTest() { Event event = Fixture.EVENT1; - Action action = new Action(event, 1L); - MemberAction memberAction = new MemberAction(action, "토다리", IN, 1L); - Action action1 = new Action(event, 2L); - MemberAction memberAction1 = new MemberAction(action1, "쿠키", IN, 1L); - Action action2 = new Action(event, 3L); - BillAction billAction = new BillAction(action2, "뽕나무쟁이족발", 30000L); + MemberAction memberAction = Fixture.createMemberAction(event, 1L, "토다리", IN); + MemberAction memberAction1 = Fixture.createMemberAction(event, 2L, "쿠키", IN); + BillAction billAction = Fixture.createBillAction(event, 3L, "뽕나무쟁이족발", 30000L); eventRepository.save(event); memberActionRepository.saveAll(List.of(memberAction, memberAction1)); billActionRepository.save(billAction); @@ -88,14 +89,14 @@ void findActionsTest() { assertThat(actionAppResponses).hasSize(3) .extracting(ActionAppResponse::actionId, - ActionAppResponse::name, - ActionAppResponse::price, - ActionAppResponse::sequence, - ActionAppResponse::actionTypeName) + ActionAppResponse::name, + ActionAppResponse::price, + ActionAppResponse::sequence, + ActionAppResponse::actionTypeName) .containsExactly( tuple(1L, "토다리", null, 1L, "IN"), tuple(2L, "쿠키", null, 2L, "IN"), - tuple(3L, "뽕나무쟁이족발", 30000L, 3L, "BILL") + tuple(1L, "뽕나무쟁이족발", 30000L, 3L, "BILL") ); } @@ -103,14 +104,10 @@ void findActionsTest() { @Test void findAllMembersTest() { Event event = Fixture.EVENT1; - Action action1 = new Action(event, 1L); - Action action2 = new Action(event, 2L); - Action action3 = new Action(event, 3L); - Action action4 = new Action(event, 4L); - BillAction billAction = new BillAction(action3, "뽕나무쟁이족발", 30000L); - MemberAction memberAction1 = new MemberAction(action1, "토다리", IN, 1L); - MemberAction memberAction2 = new MemberAction(action2, "쿠키", IN, 1L); - MemberAction memberAction3 = new MemberAction(action4, "쿠키", OUT, 1L); + BillAction billAction = Fixture.createBillAction(event, 3L, "뽕나무쟁이족발", 30000L); + MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); + MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "쿠키", IN); + MemberAction memberAction3 = Fixture.createMemberAction(event, 4L, "쿠키", OUT); eventRepository.save(event); billActionRepository.save(billAction); memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); @@ -124,12 +121,12 @@ void findAllMembersTest() { @Test void updateMember() { Event event = Fixture.EVENT1; - MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "토다리", IN, 1L); - MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "쿠키", IN, 1L); - MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "웨디", IN, 2L); - MemberAction memberAction4 = new MemberAction(new Action(event, 4L), "쿠키", OUT, 3L); - MemberAction memberAction5 = new MemberAction(new Action(event, 5L), "쿠키", IN, 4L); - MemberAction memberAction6 = new MemberAction(new Action(event, 6L), "쿠키", OUT, 5L); + MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); + MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "쿠키", IN); + MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "웨디", IN); + MemberAction memberAction4 = Fixture.createMemberAction(event, 4L, "쿠키", OUT); + MemberAction memberAction5 = Fixture.createMemberAction(event, 5L, "쿠키", IN); + MemberAction memberAction6 = Fixture.createMemberAction(event, 6L, "쿠키", OUT); eventRepository.save(event); memberActionRepository.saveAll(List.of( memberAction1, memberAction2, memberAction3, memberAction4, memberAction5, memberAction6 @@ -157,9 +154,9 @@ void updateMember() { @Test void updateMember1() { Event event = Fixture.EVENT1; - MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "토다리", IN, 1L); - MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "쿠키", IN, 1L); - MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "웨디", IN, 2L); + MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); + MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "쿠키", IN); + MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "웨디", IN); eventRepository.save(event); memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); @@ -176,9 +173,9 @@ void updateMember1() { @Test void updateMember2() { Event event = Fixture.EVENT1; - MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "토다리", IN, 1L); - MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "쿠키", IN, 1L); - MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "웨디", IN, 2L); + MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); + MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "쿠키", IN); + MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "웨디", IN); eventRepository.save(event); memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); @@ -195,9 +192,9 @@ void updateMember2() { @Test void updateMember3() { Event event = Fixture.EVENT1; - MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "토다리", IN, 1L); - MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "쿠키", IN, 1L); - MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "웨디", IN, 2L); + MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); + MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "쿠키", IN); + MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "웨디", IN); eventRepository.save(event); memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); @@ -214,9 +211,9 @@ void updateMember3() { @Test void updateMember4() { Event event = Fixture.EVENT1; - MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "토다리", IN, 1L); - MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "쿠키", IN, 1L); - MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "웨디", IN, 2L); + MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); + MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "쿠키", IN); + MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "웨디", IN); eventRepository.save(event); memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); @@ -228,4 +225,55 @@ void updateMember4() { assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) .isInstanceOf(HaengdongException.class); } + + @DisplayName("참여자별 정산 현황을 조회한다.") + @Test + void getMemberBillReports() { + Event event = Fixture.EVENT1; + Event savedEvent = eventRepository.save(event); + List<MemberAction> memberActions = List.of( + new MemberAction(savedEvent, new Sequence(1L), "소하", IN), + new MemberAction(savedEvent, new Sequence(2L), "감자", IN), + new MemberAction(savedEvent, new Sequence(3L), "쿠키", IN), + new MemberAction(savedEvent, new Sequence(5L), "감자", OUT) + ); + List<BillAction> billActions = List.of( + new BillAction(savedEvent, new Sequence(4L), "뽕족", 60_000L), + new BillAction(savedEvent, new Sequence(7L), "인생네컷", 20_000L) + ); + billActions.get(0).addDetails( + List.of( + new BillActionDetail(BILL_ACTION, "소하", 10_000L, false), + new BillActionDetail(BILL_ACTION, "감자", 40_000L, true), + new BillActionDetail(BILL_ACTION, "쿠키", 10_000L, false) + ) + ); + billActions.get(1).addDetails( + List.of( + new BillActionDetail(BILL_ACTION, "소하", 5_000L, true), + new BillActionDetail(BILL_ACTION, "쿠키", 15_000L, true) + ) + ); + memberActionRepository.saveAll(memberActions); + billActionRepository.saveAll(billActions); + + List<MemberBillReportAppResponse> responses = eventService.getMemberBillReports(event.getToken()); + + assertThat(responses) + .hasSize(3) + .extracting(MemberBillReportAppResponse::name, MemberBillReportAppResponse::price) + .containsExactlyInAnyOrder( + tuple("감자", 40_000L), + tuple("쿠키", 25_000L), + tuple("소하", 15_000L) + ); + } + + @DisplayName("존재하지 않는 이벤트의 참여자별 정산 현황을 조회하는 경우 예외가 발생한다.") + @Test + void getMemberBillReports1() { + assertThatThrownBy(() -> eventService.getMemberBillReports("invalid token")) + .isInstanceOf(HaengdongException.class) + .hasMessage(HaengdongErrorCode.EVENT_NOT_FOUND.getMessage()); + } } diff --git a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java index c04f06026..4f1156714 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java @@ -11,11 +11,11 @@ import org.springframework.beans.factory.annotation.Autowired; import server.haengdong.application.request.MemberActionSaveAppRequest; import server.haengdong.application.request.MemberActionsSaveAppRequest; -import server.haengdong.domain.action.Action; import server.haengdong.domain.action.CurrentMembers; import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionRepository; import server.haengdong.domain.action.MemberActionStatus; +import server.haengdong.domain.action.Sequence; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.exception.HaengdongException; @@ -36,10 +36,8 @@ class MemberActionFactoryTest extends ServiceTestSupport { @Test void createMemberActionsTest() { Event event = eventRepository.save(Fixture.EVENT1); - Action action1 = new Action(event, 1L); - Action action2 = new Action(event, 2L); - MemberAction memberAction1 = new MemberAction(action1, "토다리", MemberActionStatus.IN, 1L); - MemberAction memberAction2 = new MemberAction(action2, "토다리", MemberActionStatus.OUT, 2L); + MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", MemberActionStatus.IN); + MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "토다리", MemberActionStatus.OUT); memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( @@ -47,9 +45,9 @@ void createMemberActionsTest() { List<MemberAction> unorderedMemberActions = List.of(memberAction2, memberAction1); CurrentMembers currentMembers = CurrentMembers.of(unorderedMemberActions); - Action startAction = new Action(event, 3L); + Sequence sequence = new Sequence(3L); - assertThatThrownBy(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + assertThatThrownBy(() -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence)) .isInstanceOf(HaengdongException.class); } @@ -57,23 +55,23 @@ void createMemberActionsTest() { @Test void createMemberActionsTest1() { Event event = eventRepository.save(Fixture.EVENT1); - Action action = new Action(event, 1L); - MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + MemberAction memberAction = Fixture.createMemberAction(event, 1L, "토다리", MemberActionStatus.IN); memberActionRepository.save(memberAction); MemberActionsSaveAppRequest memberActionsSaveAppRequest = new MemberActionsSaveAppRequest( List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); - Action startAction = new Action(event, 2L); + Sequence sequence = new Sequence(2L); CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); - List<MemberAction> memberActions = memberActionFactory.createMemberActions(memberActionsSaveAppRequest, - currentMembers, startAction + List<MemberAction> memberActions = memberActionFactory.createMemberActions(event, memberActionsSaveAppRequest, + currentMembers, sequence ); assertThat(memberActions).hasSize(1) - .extracting(MemberAction::getAction, MemberAction::getMemberName, MemberAction::getStatus) + .extracting(MemberAction::getEvent, MemberAction::getSequence, MemberAction::getMemberName, + MemberAction::getStatus) .containsExactly( - tuple(startAction, "토다리", MemberActionStatus.OUT) + tuple(event, sequence, "토다리", MemberActionStatus.OUT) ); } @@ -81,16 +79,15 @@ void createMemberActionsTest1() { @Test void createMemberActionsTest2() { Event event = eventRepository.save(Fixture.EVENT1); - Action action = new Action(event, 1L); - MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + MemberAction memberAction = Fixture.createMemberAction(event, 1L, "토다리", MemberActionStatus.IN); memberActionRepository.save(memberAction); MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); - Action startAction = new Action(event, 2L); + Sequence sequence = new Sequence(2L); CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); - assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + assertThatCode(() -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence)) .doesNotThrowAnyException(); } @@ -98,19 +95,17 @@ void createMemberActionsTest2() { @Test void createMemberActionsTest3() { Event event = eventRepository.save(Fixture.EVENT1); - Action action1 = new Action(event, 1L); - MemberAction memberAction1 = new MemberAction(action1, "토다리", MemberActionStatus.IN, 1L); + MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", MemberActionStatus.IN); memberActionRepository.save(memberAction1); - Action action2 = new Action(event, 2L); - MemberAction memberAction2 = new MemberAction(action2, "토다리", MemberActionStatus.OUT, 2L); + MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "토다리", MemberActionStatus.OUT); memberActionRepository.save(memberAction2); MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( List.of(new MemberActionSaveAppRequest("토다리", "IN"))); - Action startAction = new Action(event, 3L); + Sequence sequence = new Sequence(3L); CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction1, memberAction2)); - assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + assertThatCode(() -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence)) .doesNotThrowAnyException(); } @@ -118,16 +113,15 @@ void createMemberActionsTest3() { @Test void createMemberActionsTest4() { Event event = eventRepository.save(Fixture.EVENT1); - Action action = new Action(event, 1L); - MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + MemberAction memberAction = Fixture.createMemberAction(event, 1L, "토다리", MemberActionStatus.IN); memberActionRepository.save(memberAction); MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); - Action startAction = new Action(event, 2L); + Sequence sequence = new Sequence(2L); CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); - assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + assertThatCode(() -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence)) .doesNotThrowAnyException(); } @@ -138,11 +132,11 @@ void createMemberActionTest5() { MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( List.of(new MemberActionSaveAppRequest("쿠키", "OUT"))); - Action startAction = new Action(event, 2L); + Sequence sequence = new Sequence(2L); CurrentMembers currentMembers = CurrentMembers.of(List.of()); assertThatCode( - () -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + () -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence)) .isInstanceOf(HaengdongException.class); } @@ -150,16 +144,15 @@ void createMemberActionTest5() { @Test void createMemberActionTest6() { Event event = eventRepository.save(Fixture.EVENT1); - Action action = new Action(event, 1L); - MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); + MemberAction memberAction = Fixture.createMemberAction(event, 1L, "쿠키", MemberActionStatus.IN); memberActionRepository.save(memberAction); MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); - Action startAction = new Action(event, 2L); + Sequence sequence = new Sequence(2L); CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); - assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + assertThatCode(() -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence)) .isInstanceOf(HaengdongException.class); } @@ -173,11 +166,11 @@ void createMemberActionTest7() { new MemberActionSaveAppRequest("쿠키", "IN"), new MemberActionSaveAppRequest("쿠키", "IN") )); - Action startAction = new Action(event, 1L); + Sequence sequence = new Sequence(1L); CurrentMembers currentMembers = CurrentMembers.of(List.of()); assertThatCode( - () -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + () -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence)) .isInstanceOf(HaengdongException.class); } @@ -185,8 +178,8 @@ void createMemberActionTest7() { @Test void createMemberActionTest8() { Event event = eventRepository.save(Fixture.EVENT1); - Action action = new Action(event, 1L); - MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); + Sequence sequence1 = new Sequence(1L); + MemberAction memberAction = new MemberAction(event, sequence1, "쿠키", MemberActionStatus.IN); memberActionRepository.save(memberAction); MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( @@ -194,10 +187,10 @@ void createMemberActionTest8() { new MemberActionSaveAppRequest("쿠키", "OUT"), new MemberActionSaveAppRequest("쿠키", "OUT") )); - Action startAction = new Action(event, 2L); + Sequence sequence2 = new Sequence(2L); CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); - assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + assertThatCode(() -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence2)) .isInstanceOf(HaengdongException.class); } @@ -205,8 +198,8 @@ void createMemberActionTest8() { @Test void createMemberActionTest9() { Event event = eventRepository.save(Fixture.EVENT1); - Action action = new Action(event, 1L); - MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); + Sequence sequence = new Sequence(1L); + MemberAction memberAction = new MemberAction(event, sequence, "쿠키", MemberActionStatus.IN); memberActionRepository.save(memberAction); MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( @@ -214,10 +207,10 @@ void createMemberActionTest9() { new MemberActionSaveAppRequest("쿠키", "IN"), new MemberActionSaveAppRequest("쿠키", "OUT") )); - Action startAction = new Action(event, 2L); + Sequence sequence2 = new Sequence(2L); CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); - assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + assertThatCode(() -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence2)) .isInstanceOf(HaengdongException.class); } } diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java index b6d29444c..51f5428f0 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java @@ -13,14 +13,12 @@ import org.springframework.beans.factory.annotation.Autowired; import server.haengdong.application.request.MemberActionSaveAppRequest; import server.haengdong.application.request.MemberActionsSaveAppRequest; -import server.haengdong.domain.action.Action; import server.haengdong.domain.action.BillAction; import server.haengdong.domain.action.BillActionDetail; import server.haengdong.domain.action.BillActionDetailRepository; import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionRepository; -import server.haengdong.domain.action.MemberActionStatus; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.exception.HaengdongException; @@ -47,8 +45,7 @@ class MemberActionServiceTest extends ServiceTestSupport { @Test void saveMemberActionTest() { Event event = eventRepository.save(Fixture.EVENT1); - Action action = new Action(event, 1L); - MemberAction memberAction = new MemberAction(action, "망쵸", IN, 1L); + MemberAction memberAction = Fixture.createMemberAction(event, 1L, "망쵸", IN); memberActionRepository.save(memberAction); assertThatCode(() -> memberActionService.saveMemberAction(event.getToken(), new MemberActionsSaveAppRequest( @@ -60,12 +57,10 @@ void saveMemberActionTest() { @Test void saveMemberActionTest1() { Event event = eventRepository.save(Fixture.EVENT1); - Action actionOne = new Action(event, 1L); - MemberAction memberActionOne = new MemberAction(actionOne, "망쵸", IN, 1L); + MemberAction memberActionOne = Fixture.createMemberAction(event, 1L, "망쵸", IN); memberActionRepository.save(memberActionOne); - Action actionTwo = new Action(event, 2L); - MemberAction memberActionTwo = new MemberAction(actionTwo, "망쵸", OUT, 1L); + MemberAction memberActionTwo = Fixture.createMemberAction(event, 2L, "망쵸", OUT); memberActionRepository.save(memberActionTwo); assertThatCode(() -> memberActionService.saveMemberAction(event.getToken(), new MemberActionsSaveAppRequest( @@ -95,19 +90,18 @@ void getCurrentMembers() { void deleteMember() { Event event = Fixture.EVENT1; eventRepository.save(event); - MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "참여자", IN, 1L); - MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "토다리", IN, 1L); - MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "쿠키", IN, 1L); - MemberAction memberAction4 = new MemberAction(new Action(event, 4L), "소하", IN, 1L); - MemberAction memberAction5 = new MemberAction(new Action(event, 5L), "웨디", IN, 1L); - MemberAction memberAction6 = new MemberAction(new Action(event, 6L), "참여자", OUT, 1L); + MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "참여자", IN); + MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "토다리", IN); + MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "쿠키", IN); + MemberAction memberAction4 = Fixture.createMemberAction(event, 4L, "소하", IN); + MemberAction memberAction5 = Fixture.createMemberAction(event, 5L, "웨디", IN); + MemberAction memberAction6 = Fixture.createMemberAction(event, 6L, "참여자", OUT); memberActionRepository.saveAll( List.of(memberAction1, memberAction2, memberAction3, memberAction4, memberAction5, memberAction6)); Event event2 = Fixture.EVENT2; eventRepository.save(event2); - Action action2 = Action.createFirst(event2); - MemberAction anotherMemberAction = new MemberAction(action2, "참여자", IN, 1L); + MemberAction anotherMemberAction = Fixture.createMemberAction(event2, 1L, "참여자", IN); memberActionRepository.save(anotherMemberAction); memberActionService.deleteMember(event.getToken(), "참여자"); @@ -130,12 +124,11 @@ void deleteMember() { void deleteMember1() { Event event = Fixture.EVENT1; eventRepository.save(event); - MemberAction memberAction1 = createMemberAction(new Action(event, 1L), "토다리", IN, 1L); - Action targetAction = new Action(event, 2L); - MemberAction memberAction2 = createMemberAction(targetAction, "토다리", OUT, 2L); - MemberAction memberAction3 = createMemberAction(new Action(event, 3L), "쿠키", IN, 3L); - MemberAction memberAction4 = createMemberAction(new Action(event, 4L), "웨디", IN, 4L); - MemberAction memberAction5 = createMemberAction(new Action(event, 5L), "감자", IN, 5L); + MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); + MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "토다리", OUT); + MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "쿠키", IN); + MemberAction memberAction4 = Fixture.createMemberAction(event, 4L, "웨디", IN); + MemberAction memberAction5 = Fixture.createMemberAction(event, 5L, "감자", IN); memberActionRepository.saveAll( List.of(memberAction1, memberAction2, @@ -144,14 +137,12 @@ void deleteMember1() { memberAction5 ) ); - BillAction billAction = new BillAction(new Action(event, 6L), "뽕족", 100_000L); + BillAction billAction = Fixture.createBillAction(event, 6L, "뽕족", 100_000L); billActionRepository.save(billAction); BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "쿠키", 40_000L, true); BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "웨디", 30_000L, false); BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "감자", 30_000L, false); billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3)); - List<BillActionDetail> allByBillAction = billActionDetailRepository.findAllByBillAction(billAction); - System.out.println("allByBillAction = " + allByBillAction.isEmpty()); memberActionService.deleteMember(event.getToken(), "쿠키"); @@ -170,14 +161,13 @@ void deleteMember1() { void deleteMemberAction() { Event event = Fixture.EVENT1; eventRepository.save(event); - MemberAction memberAction1 = createMemberAction(new Action(event, 1L), "토다리", IN, 1L); - Action targetAction = new Action(event, 2L); - MemberAction memberAction2 = createMemberAction(targetAction, "토다리", OUT, 2L); - MemberAction memberAction3 = createMemberAction(new Action(event, 3L), "쿠키", IN, 3L); - MemberAction memberAction4 = createMemberAction(new Action(event, 4L), "웨디", IN, 4L); - MemberAction memberAction5 = createMemberAction(new Action(event, 5L), "토다리", IN, 5L); - MemberAction memberAction6 = createMemberAction(new Action(event, 6L), "토다리", OUT, 6L); - MemberAction memberAction7 = createMemberAction(new Action(event, 7L), "쿠키", OUT, 7L); + MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); + MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "토다리", OUT); + MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "쿠키", IN); + MemberAction memberAction4 = Fixture.createMemberAction(event, 4L, "웨디", IN); + MemberAction memberAction5 = Fixture.createMemberAction(event, 5L, "토다리", IN); + MemberAction memberAction6 = Fixture.createMemberAction(event, 6L, "토다리", OUT); + MemberAction memberAction7 = Fixture.createMemberAction(event, 7L, "쿠키", OUT); memberActionRepository.saveAll( List.of(memberAction1, memberAction2, @@ -188,7 +178,7 @@ void deleteMemberAction() { memberAction7) ); - memberActionService.deleteMemberAction(event.getToken(), targetAction.getId()); + memberActionService.deleteMemberAction(event.getToken(), memberAction2.getId()); List<MemberAction> memberActions = memberActionRepository.findAll(); assertThat(memberActions).hasSize(4) @@ -206,12 +196,11 @@ void deleteMemberAction() { void deleteMemberAction1() { Event event = Fixture.EVENT1; eventRepository.save(event); - MemberAction memberAction1 = createMemberAction(new Action(event, 1L), "토다리", IN, 1L); - Action targetAction = new Action(event, 2L); - MemberAction memberAction2 = createMemberAction(targetAction, "토다리", OUT, 2L); - MemberAction memberAction3 = createMemberAction(new Action(event, 3L), "쿠키", IN, 3L); - MemberAction memberAction4 = createMemberAction(new Action(event, 4L), "웨디", IN, 4L); - MemberAction memberAction5 = createMemberAction(new Action(event, 5L), "감자", IN, 5L); + MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); + MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "토다리", OUT); + MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "쿠키", IN); + MemberAction memberAction4 = Fixture.createMemberAction(event, 4L, "웨디", IN); + MemberAction memberAction5 = Fixture.createMemberAction(event, 5L, "감자", IN); memberActionRepository.saveAll( List.of(memberAction1, memberAction2, @@ -220,14 +209,14 @@ void deleteMemberAction1() { memberAction5 ) ); - BillAction billAction = new BillAction(new Action(event, 6L), "뽕족", 100_000L); + BillAction billAction = Fixture.createBillAction(event, 6L, "뽕족", 100_000L); billActionRepository.save(billAction); BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "쿠키", 40_000L, true); BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "웨디", 30_000L, false); BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "감자", 30_000L, false); billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3)); - memberActionService.deleteMemberAction(event.getToken(), targetAction.getId()); + memberActionService.deleteMemberAction(event.getToken(), memberAction2.getId()); List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(billAction); assertThat(billActionDetails).hasSize(4) @@ -239,13 +228,4 @@ void deleteMemberAction1() { tuple("감자", 25_000L) ); } - - private MemberAction createMemberAction( - Action action, - String memberName, - MemberActionStatus memberActionStatus, - long memberGroupId - ) { - return new MemberAction(action, memberName, memberActionStatus, memberGroupId); - } } diff --git a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java index 202b64fcf..6950f3d23 100644 --- a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java @@ -30,7 +30,6 @@ import org.springframework.http.MediaType; import org.springframework.restdocs.payload.JsonFieldType; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; -import server.haengdong.application.ActionService; import server.haengdong.application.AuthService; import server.haengdong.application.EventService; import server.haengdong.application.request.EventAppRequest; @@ -49,14 +48,13 @@ public class EventControllerDocsTest extends RestDocsSupport { private final EventService eventService = mock(EventService.class); private final AuthService authService = mock(AuthService.class); - private final ActionService actionService = mock(ActionService.class); private final CookieProperties cookieProperties = new CookieProperties( true, true, "domain", "path", "none", Duration.ofDays(7) ); @Override protected Object initController() { - return new EventController(eventService, authService, cookieProperties, actionService); + return new EventController(eventService, authService, cookieProperties); } @DisplayName("토큰으로 행사를 조회한다.") @@ -253,7 +251,7 @@ void getMemberBillReports() throws Exception { List<MemberBillReportAppResponse> memberBillReportAppResponses = List.of( new MemberBillReportAppResponse("소하", 20_000L), new MemberBillReportAppResponse("토다리", 200_000L)); - given(actionService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); + given(eventService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); mockMvc.perform(get("/api/events/{eventId}/reports", "망쵸토큰") .accept(MediaType.APPLICATION_JSON)) diff --git a/server/src/test/java/server/haengdong/domain/action/ActionTest.java b/server/src/test/java/server/haengdong/domain/action/ActionTest.java deleted file mode 100644 index 6ff25479c..000000000 --- a/server/src/test/java/server/haengdong/domain/action/ActionTest.java +++ /dev/null @@ -1,31 +0,0 @@ -package server.haengdong.domain.action; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import server.haengdong.domain.event.Event; -import server.haengdong.support.fixture.Fixture; - -class ActionTest { - - @DisplayName("액션의 초기 순서번호는 1이다.") - @Test - void createFirst() { - Event event = Fixture.EVENT1; - Action action = Action.createFirst(event); - - assertThat(action.getSequence()).isOne(); - } - - @DisplayName("현재 액션의 다음 액션의 순서는 1만큼 증가한다.") - @Test - void next() { - Event event = Fixture.EVENT1; - Action action = new Action(event, 2L); - - Action nextAction = action.next(); - - assertThat(nextAction.getSequence()).isEqualTo(3L); - } -} diff --git a/server/src/test/java/server/haengdong/domain/action/BillActionTest.java b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java index ba1ab36f2..d66202663 100644 --- a/server/src/test/java/server/haengdong/domain/action/BillActionTest.java +++ b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java @@ -11,8 +11,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import server.haengdong.domain.event.Event; import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; class BillActionTest { @@ -20,11 +20,10 @@ class BillActionTest { @ParameterizedTest @ValueSource(strings = {"", " ", "1234567890123456789012345678901"}) void validateTitle(String title) { - Event event = EVENT1; - Action action = new Action(event, 1L); + Sequence sequence = new Sequence(1L); Long price = 100L; - assertThatThrownBy(() -> new BillAction(action, title, price)) + assertThatThrownBy(() -> new BillAction(EVENT1, sequence, title, price)) .isInstanceOf(HaengdongException.class) .hasMessage("앞뒤 공백을 제거한 지출 내역 제목은 1 ~ 30자여야 합니다."); } @@ -33,11 +32,10 @@ void validateTitle(String title) { @ParameterizedTest @ValueSource(longs = {0, 10_000_001, 20_000_000}) void validatePrice(long price) { - Event event = EVENT1; - Action action = new Action(event, 1L); + Sequence sequence = new Sequence(1L); String title = "title"; - assertThatThrownBy(() -> new BillAction(action, title, price)) + assertThatThrownBy(() -> new BillAction(EVENT1, sequence, title, price)) .isInstanceOf(HaengdongException.class) .hasMessage("지출 금액은 10,000,000 이하의 자연수여야 합니다."); } @@ -45,15 +43,14 @@ void validatePrice(long price) { @DisplayName("지출 내역을 올바르게 생성한다.") @Test void createBillAction() { - Event event = EVENT1; - Action action = new Action(event, 1L); + Sequence sequence = new Sequence(1L); String title = "title"; Long price = 1_000L; - BillAction billAction = new BillAction(action, title, price); + BillAction billAction = new BillAction(EVENT1, sequence, title, price); assertAll( - () -> assertThat(billAction.getAction()).isEqualTo(action), + () -> assertThat(billAction.getSequence().getValue()).isEqualTo(1L), () -> assertThat(billAction.getTitle()).isEqualTo(title), () -> assertThat(billAction.getPrice()).isEqualTo(price) ); @@ -62,7 +59,7 @@ void createBillAction() { @DisplayName("지출 액션에 멤버별 고정 금액이 설정되어 있는지 확인한다.") @Test void isFixed1() { - BillAction fixedBillAction = new BillAction(new Action(EVENT1, 1L), "인생네컷", 2_000L); + BillAction fixedBillAction = Fixture.createBillAction(EVENT1, 1L, "인생네컷", 2_000L); List<BillActionDetail> unfixedBillActionDetails = List.of( new BillActionDetail(BILL_ACTION, "감자", 1_000L, false), @@ -76,7 +73,7 @@ void isFixed1() { @DisplayName("지출 액션에 멤버별 고정 금액이 설정되어 있는지 확인한다.") @Test void isFixed2() { - BillAction fixedBillAction = new BillAction(new Action(EVENT1, 1L), "인생네컷", 5_000L); + BillAction fixedBillAction = Fixture.createBillAction(EVENT1, 1L, "인생네컷", 5_000L); List<BillActionDetail> unfixedBillActionDetails = List.of( new BillActionDetail(BILL_ACTION, "감자", 4_000L, true), diff --git a/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java b/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java index 93148abd3..95eab19cc 100644 --- a/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java +++ b/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java @@ -20,10 +20,10 @@ class CurrentMembersTest { void of() { Event event = Fixture.EVENT1; List<MemberAction> memberActions = List.of( - new MemberAction(new Action(event, 1L), "망쵸", IN, 1L), - new MemberAction(new Action(event, 2L), "백호", IN, 1L), - new MemberAction(new Action(event, 3L), "백호", OUT, 1L), - new MemberAction(new Action(event, 4L), "웨디", IN, 1L) + Fixture.createMemberAction(event, 1L, "망쵸", IN), + Fixture.createMemberAction(event, 2L, "백호", IN), + Fixture.createMemberAction(event, 3L, "백호", OUT), + Fixture.createMemberAction(event, 4L, "웨디", IN) ); CurrentMembers currentMembers = CurrentMembers.of(memberActions); @@ -37,7 +37,7 @@ void of() { void addMemberAction1() { CurrentMembers currentMembers = new CurrentMembers(); Event event = Fixture.EVENT1; - MemberAction memberAction = new MemberAction(new Action(event, 1L), "웨디", IN, 1L); + MemberAction memberAction = Fixture.createMemberAction(event, 1L, "웨디", IN); CurrentMembers addedCurrentMembers = currentMembers.addMemberAction(memberAction); Set<String> members = addedCurrentMembers.getMembers(); @@ -50,9 +50,9 @@ void addMemberAction1() { @Test void addMemberAction2() { Event event = Fixture.EVENT1; - MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "웨디", IN, 1L); + MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "웨디", IN); CurrentMembers currentMembers = new CurrentMembers().addMemberAction(memberAction1); - MemberAction memberAction2 = new MemberAction(new Action(event, 1L), "웨디", OUT, 1L); + MemberAction memberAction2 = Fixture.createMemberAction(event, 1L, "웨디", OUT); CurrentMembers addedCurrentMembers = currentMembers.addMemberAction(memberAction2); diff --git a/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java b/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java index 02070a537..4a009d2df 100644 --- a/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java +++ b/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java @@ -19,8 +19,8 @@ class MemberBillReportTest { void createByActions() { Event event = Fixture.EVENT1; List<BillAction> billActions = List.of( - new BillAction(new Action(event, 4L), "뽕족", 60_000L), - new BillAction(new Action(event, 7L), "인생네컷", 20_000L) + Fixture.createBillAction(event, 4L, "뽕족", 60_000L), + Fixture.createBillAction(event, 7L, "인생네컷", 20_000L) ); billActions.get(0).addDetails( List.of( @@ -36,10 +36,10 @@ void createByActions() { ) ); List<MemberAction> memberActions = List.of( - new MemberAction(new Action(event, 1L), "소하", IN, 1L), - new MemberAction(new Action(event, 2L), "감자", IN, 1L), - new MemberAction(new Action(event, 3L), "쿠키", IN, 1L), - new MemberAction(new Action(event, 5L), "감자", OUT, 2L) + Fixture.createMemberAction(event, 1L, "소하", IN), + Fixture.createMemberAction(event, 2L, "감자", IN), + Fixture.createMemberAction(event, 3L, "쿠키", IN), + Fixture.createMemberAction(event, 5L, "감자", OUT) ); MemberBillReport memberBillReport = MemberBillReport.createByActions(billActions, memberActions); diff --git a/server/src/test/java/server/haengdong/domain/action/SequenceTest.java b/server/src/test/java/server/haengdong/domain/action/SequenceTest.java new file mode 100644 index 000000000..d2277d593 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/action/SequenceTest.java @@ -0,0 +1,27 @@ +package server.haengdong.domain.action; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class SequenceTest { + + @DisplayName("액션의 초기 순서번호는 1이다.") + @Test + void createFirst() { + Sequence sequence = Sequence.createFirst(); + + assertThat(sequence.getValue()).isOne(); + } + + @DisplayName("현재 액션의 다음 액션의 순서는 1만큼 증가한다.") + @Test + void next() { + Sequence sequence = new Sequence(2L); + + Sequence nextAction = sequence.next(); + + assertThat(nextAction.getValue()).isEqualTo(3L); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java b/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java index c20043381..f5964e897 100644 --- a/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java +++ b/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java @@ -8,7 +8,6 @@ import org.springframework.context.annotation.FilterType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import server.haengdong.application.ActionService; import server.haengdong.application.AuthService; import server.haengdong.application.BillActionDetailService; import server.haengdong.application.BillActionService; @@ -43,9 +42,6 @@ public abstract class ControllerTestSupport { @MockBean protected AuthService authService; - @MockBean - protected ActionService actionService; - @MockBean protected MemberActionService memberActionService; diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java index a45c73230..a58924a32 100644 --- a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java @@ -60,7 +60,7 @@ void getMemberBillReports() throws Exception { List<MemberBillReportAppResponse> memberBillReportAppResponses = List.of( new MemberBillReportAppResponse("소하", 20_000L), new MemberBillReportAppResponse("토다리", 200_000L)); - given(actionService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); + given(eventService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); mockMvc.perform(get("/api/events/{eventId}/reports", "망쵸토큰") .accept(MediaType.APPLICATION_JSON)) diff --git a/server/src/test/java/server/haengdong/support/fixture/Fixture.java b/server/src/test/java/server/haengdong/support/fixture/Fixture.java index 6844915d9..b8d736d4b 100644 --- a/server/src/test/java/server/haengdong/support/fixture/Fixture.java +++ b/server/src/test/java/server/haengdong/support/fixture/Fixture.java @@ -1,8 +1,10 @@ package server.haengdong.support.fixture; import jakarta.servlet.http.Cookie; -import server.haengdong.domain.action.Action; import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionStatus; +import server.haengdong.domain.action.Sequence; import server.haengdong.domain.event.Event; public class Fixture { @@ -10,6 +12,15 @@ public class Fixture { public static final Event EVENT1 = new Event("쿠키", "1234", "TOKEN1"); public static final Event EVENT2 = new Event("웨디", "1234", "TOKEN2"); public static final Cookie EVENT_COOKIE = new Cookie("eventToken", "토큰토큰"); - public static final Action ACTION = new Action(EVENT1, 1L); - public static final BillAction BILL_ACTION = new BillAction(ACTION, "뽕족", 30_000L); + public static final BillAction BILL_ACTION = new BillAction(EVENT1, new Sequence(1L), "뽕족", 30_000L); + + public static BillAction createBillAction(Event event, Long sequence, String title, Long price) { + return new BillAction(event, new Sequence(sequence), title, price); + } + + public static MemberAction createMemberAction( + Event event, Long sequence, String memberName, MemberActionStatus status + ) { + return new MemberAction(event, new Sequence(sequence), memberName, status); + } } From ce7428741acdc96e2b94d83d1ad3a982cfe2fcce Mon Sep 17 00:00:00 2001 From: Juhwan Kim <13selfesteem91@naver.com> Date: Thu, 19 Sep 2024 14:34:09 +0900 Subject: [PATCH 169/178] =?UTF-8?q?refactor:=20=EB=B3=80=EA=B2=BD=EB=90=9C?= =?UTF-8?q?=20=EC=9A=94=EA=B5=AC=EC=82=AC=ED=95=AD=EC=97=90=20=EB=A7=9E?= =?UTF-8?q?=EA=B2=8C=20API=20=EC=A0=84=EC=B2=B4=20=EC=88=98=EC=A0=95=20(#5?= =?UTF-8?q?58)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: Member 엔티티 추가 Co-authored-by: Arachneee <jhg2819@naver.com> * refactor: MemberAction 삭제 * test: 테스트 제 * test: 지출 고정 금액 수정, 삭제, 행사 조회, 정산 조회 테스트 추가 * test: MemberAction 제거로 인한 Bill 도메인의 테스트 변경사항 반영 to feature/#546 (#557) * test: BillController, BillService 지출 전체 조회 테스트 작성 * test: 참여자별 지출 고정 금액 조회 테스트 추가 * test: 지출 내역 추가 테스트 작성 * test: 지출 수정 테스트 작성 * refactor: docsTest responseFields 추가 및 액션이름 제거 * refactor: docsTest responseFields 추가 및 액션이름 제거 * test: 행사 도메인 테스트 변경 * feat: 행사 정보 수정 API 구현 * test: 테스트에 필요한 의존성 주입 * test: 행사 정보 업데이트 컨트롤러 테스트 * test: 행사 정보 업데이트 서비스 테스트 * test: 이벤트 도메인에 계좌 정보 설정 테스트 * test: 행사 업데이트 API 레독 테스트 * test: 행사 전체 참여 인원 조회 컨트롤러 테스트 * test: 행사 전체 참여 인원 조회 서비스 테스트 * test: 행사 전체 참여 인원 조회 API 레독 테스트 * test: 현재 참여 인원 API 관련 메서드 이동 * test: 현재 참여 인원 컨트롤러 테스트 * refactor: '현재 참여 인원 조회' 서비스 메서드명 수정 * test: '현재 참여 인원 조회' 레독 테스트 작성 * test: '현재 참여 인원 조회' 서비스 테스트 * test: 레독 테스트 수정 * test: 레독 테스트에 필수가 아닌 필드 값에 optional 설정 * refactor: 의미가 명확한 DTO를 사용하게 수정 * test: 현재 멤버 조회 기능 서비스 테스트 * test: 은행 정보를 enum으로 분리 * test: 새로운 API 구현, 테스트 작성 - part3 (#561) * refactor: 참여자 생성 시 예외 형식 문서에 맞게 수정 * test: 참여자 추가 기능 테스트 * docs: 멤버 추가 예외 메시지 수정 * refactor: 멤버 삭제 로직 수정 * test: 멤버 삭제 테스트 * docs: 멤버 삭제 예외 수정 * test: 행사 참여자 정보 수정 컨트롤러 테스트 * docs: 참여자 정보 수정 * refactor: 참여자 정보 수정 검증 로직 변경 * test: 참여자 정보 수정 서비스 테스트 * test: 참여자 추가 테스트 수정 * refactor: 멤버 삭제 로직 수정 * refactor: updateMembers 메서드 삭제 * test: MemberService 테스트 수정 * refactor: 토큰 불일치 시 예외 던지도록 수정 * refactor: BillDetail 삭제 쿼리 한 번만 날리도록 수정 * test: 프로덕션 동작에 맞게 테스트 코드 수정 * refactor: 테스트에서만 사용하는 메서드 삭제 * refactor: 이름 중복 확인 로직 메서드로 분리 * [BE] 새로운 API 구현, 테스트 작성 - part4 (#566) * refactor: 불필요 메소드 클래스 제거 및 액션 삭제 * refactor: Step 생성 로직 도메인으로 위임 * style: 주석 제거 * refactor: api 수정 --------- Co-authored-by: juha <khabh@naver.com> Co-authored-by: Arachneee <jhg2819@naver.com> Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Co-authored-by: JUHA <84626225+khabh@users.noreply.github.com> Co-authored-by: Arachne <66822642+Arachneee@users.noreply.github.com> --- .../asciidoc/{billAction.adoc => bill.adoc} | 24 +- ...{billActionDetail.adoc => billDetail.adoc} | 14 +- server/src/docs/asciidoc/event.adoc | 14 +- server/src/docs/asciidoc/index.adoc | 6 +- server/src/docs/asciidoc/member.adoc | 152 ++++++++ server/src/docs/asciidoc/memberAction.adoc | 100 ----- .../application/BillActionDetailService.java | 78 ---- .../application/BillActionService.java | 85 ---- .../haengdong/application/BillService.java | 155 ++++++++ .../haengdong/application/EventService.java | 156 ++------ .../application/MemberActionFactory.java | 60 --- .../application/MemberActionService.java | 100 ----- .../haengdong/application/MemberService.java | 171 ++++++++ .../request/BillActionAppRequest.java | 16 - .../BillActionDetailsUpdateAppRequest.java | 8 - .../application/request/BillAppRequest.java | 17 + ...t.java => BillDetailUpdateAppRequest.java} | 4 +- .../request/BillDetailsUpdateAppRequest.java | 8 + ...Request.java => BillUpdateAppRequest.java} | 2 +- .../request/EventUpdateAppRequest.java | 17 + .../request/MemberActionSaveAppRequest.java | 13 - .../request/MemberActionsSaveAppRequest.java | 6 - .../request/MemberNameUpdateAppRequest.java | 4 +- .../request/MemberSaveAppRequest.java | 4 + .../request/MemberUpdateAppRequest.java | 16 + .../request/MembersSaveAppRequest.java | 8 + .../request/MembersUpdateAppRequest.java | 6 + .../response/ActionAppResponse.java | 61 --- .../response/BillActionDetailAppResponse.java | 18 - .../BillActionDetailsAppResponse.java | 14 - .../application/response/BillAppResponse.java | 14 + .../response/BillDetailAppResponse.java | 20 + .../response/BillDetailsAppResponse.java | 14 + .../response/CurrentMemberAppResponse.java | 10 - .../response/EventDetailAppResponse.java | 7 +- .../response/LastBillMemberAppResponse.java | 10 + .../response/MemberAppResponse.java | 12 + .../response/MemberBillReportAppResponse.java | 7 +- .../response/MemberDepositAppResponse.java | 13 + .../response/MemberSaveAppResponse.java | 12 + .../response/MembersAppResponse.java | 8 - .../response/MembersDepositAppResponse.java | 15 + .../response/MembersSaveAppResponse.java | 16 + .../application/response/StepAppResponse.java | 21 + .../haengdong/config/AdminInterceptor.java | 2 - .../action/BillActionDetailRepository.java | 20 - .../domain/action/BillActionRepository.java | 31 -- .../domain/action/CurrentMembers.java | 81 ---- .../haengdong/domain/action/MemberAction.java | 84 ---- .../domain/action/MemberActionRepository.java | 61 --- .../domain/action/MemberActionStatus.java | 19 - .../domain/action/MemberBillReport.java | 75 ---- .../haengdong/domain/action/Sequence.java | 41 -- .../BillAction.java => bill/Bill.java} | 102 +++-- .../BillDetail.java} | 34 +- .../domain/bill/BillDetailRepository.java | 26 ++ .../haengdong/domain/bill/BillRepository.java | 15 + .../server/haengdong/domain/event/Bank.java | 56 +++ .../server/haengdong/domain/event/Event.java | 38 +- .../haengdong/domain/event/EventImage.java | 30 ++ .../haengdong/domain/member/Member.java | 79 ++++ .../domain/member/MemberBillReport.java | 31 ++ .../domain/member/MemberRepository.java | 10 + .../server/haengdong/domain/step/Step.java | 50 +++ .../server/haengdong/domain/step/Steps.java | 33 ++ .../exception/HaengdongErrorCode.java | 37 +- .../BillActionDetailController.java | 27 -- .../presentation/BillController.java | 35 ++ .../presentation/EventController.java | 26 -- ...nController.java => MemberController.java} | 20 +- .../admin/AdminBillActionController.java | 66 ---- .../admin/AdminBillController.java | 64 +++ .../admin/AdminEventController.java | 17 +- .../admin/AdminMemberActionController.java | 48 --- .../admin/AdminMemberController.java | 55 +++ .../BillActionDetailUpdateRequest.java | 21 - .../BillActionDetailsUpdateRequest.java | 16 - .../request/BillActionsSaveRequest.java | 18 - .../request/BillDetailUpdateRequest.java | 20 + .../request/BillDetailsUpdateRequest.java | 16 + ...pdateRequest.java => BillSaveRequest.java} | 16 +- ...aveRequest.java => BillUpdateRequest.java} | 9 +- .../request/EventUpdateRequest.java | 14 + .../request/MemberActionsSaveRequest.java | 25 -- .../request/MemberNameUpdateRequest.java | 9 +- .../request/MemberNamesUpdateRequest.java | 9 +- .../request/MemberSaveRequest.java | 4 + .../request/MemberUpdateRequest.java | 22 ++ .../request/MembersSaveRequest.java | 14 + .../request/MembersUpdateRequest.java | 20 + .../presentation/response/ActionResponse.java | 26 -- .../response/ActionResponse2.java | 22 -- .../response/ActionsResponse.java | 14 - .../response/BillActionDetailResponse.java | 18 - .../response/BillActionDetailsResponse.java | 16 - .../response/BillDetailResponse.java | 20 + .../response/BillDetailsResponse.java | 16 + .../presentation/response/BillResponse.java | 14 + .../response/CurrentMembersResponse.java | 11 +- .../response/EventDetailResponse.java | 7 +- .../response/MemberBillReportResponse.java | 14 +- .../response/MemberDepositResponse.java | 14 + .../presentation/response/MemberResponse.java | 18 + .../response/MemberSaveResponse.java | 12 + .../response/MembersResponse.java | 11 +- .../response/MembersSaveResponse.java | 16 + .../presentation/response/StepResponse.java | 29 +- .../presentation/response/StepsResponse.java | 60 +-- .../BillActionDetailServiceTest.java | 111 ------ .../application/BillActionServiceTest.java | 229 ----------- .../application/BillServiceTest.java | 308 +++++++++++++++ .../application/EventServiceTest.java | 246 +++--------- .../application/MemberActionFactoryTest.java | 216 ----------- .../application/MemberActionServiceTest.java | 231 ----------- .../application/MemberServiceTest.java | 364 ++++++++++++++++++ ....java => AdminBillControllerDocsTest.java} | 101 +++-- .../docs/AdminEventControllerDocsTest.java | 60 ++- .../AdminMemberActionControllerDocsTest.java | 121 ------ .../docs/AdminMemberControllerDocsTest.java | 173 +++++++++ .../BillActionDetailControllerDocsTest.java | 79 ---- .../docs/BillControllerDocsTest.java | 119 ++++++ .../docs/EventControllerDocsTest.java | 192 +-------- .../docs/MemberActionControllerDocsTest.java | 66 ---- .../docs/MemberControllerDocsTest.java | 120 ++++++ .../domain/action/BillActionTest.java | 86 ----- .../domain/action/CurrentMembersTest.java | 97 ----- .../domain/action/MemberBillReportTest.java | 56 --- .../haengdong/domain/action/SequenceTest.java | 27 -- .../haengdong/domain/bill/BillTest.java | 98 +++++ .../haengdong/domain/event/EventTest.java | 74 +++- .../domain/member/MemberBillReportTest.java | 41 ++ .../haengdong/domain/step/StepTest.java | 50 +++ .../haengdong/domain/step/StepsTest.java | 48 +++ .../presentation/ActionControllerTest.java | 4 - .../BillActionDetailControllerTest.java | 32 -- .../presentation/BillControllerTest.java | 66 ++++ .../presentation/ControllerTestSupport.java | 24 +- .../presentation/EventControllerTest.java | 32 +- .../MemberActionControllerTest.java | 34 -- .../presentation/MemberControllerTest.java | 77 ++++ ...Test.java => AdminBillControllerTest.java} | 65 ++-- .../admin/AdminEventControllerTest.java | 23 +- .../AdminMemberActionControllerTest.java | 53 --- .../admin/AdminMemberControllerTest.java | 90 +++++ .../response/StepsResponseTest.java | 63 --- .../haengdong/support/fixture/Fixture.java | 22 +- 146 files changed, 3548 insertions(+), 3750 deletions(-) rename server/src/docs/asciidoc/{billAction.adoc => bill.adoc} (77%) rename server/src/docs/asciidoc/{billActionDetail.adoc => billDetail.adoc} (78%) create mode 100644 server/src/docs/asciidoc/member.adoc delete mode 100644 server/src/docs/asciidoc/memberAction.adoc delete mode 100644 server/src/main/java/server/haengdong/application/BillActionDetailService.java delete mode 100644 server/src/main/java/server/haengdong/application/BillActionService.java create mode 100644 server/src/main/java/server/haengdong/application/BillService.java delete mode 100644 server/src/main/java/server/haengdong/application/MemberActionFactory.java delete mode 100644 server/src/main/java/server/haengdong/application/MemberActionService.java create mode 100644 server/src/main/java/server/haengdong/application/MemberService.java delete mode 100644 server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java delete mode 100644 server/src/main/java/server/haengdong/application/request/BillActionDetailsUpdateAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/BillAppRequest.java rename server/src/main/java/server/haengdong/application/request/{BillActionDetailUpdateAppRequest.java => BillDetailUpdateAppRequest.java} (58%) create mode 100644 server/src/main/java/server/haengdong/application/request/BillDetailsUpdateAppRequest.java rename server/src/main/java/server/haengdong/application/request/{BillActionUpdateAppRequest.java => BillUpdateAppRequest.java} (69%) create mode 100644 server/src/main/java/server/haengdong/application/request/EventUpdateAppRequest.java delete mode 100644 server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java delete mode 100644 server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/MemberSaveAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/MemberUpdateAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/MembersSaveAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/MembersUpdateAppRequest.java delete mode 100644 server/src/main/java/server/haengdong/application/response/ActionAppResponse.java delete mode 100644 server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java delete mode 100644 server/src/main/java/server/haengdong/application/response/BillActionDetailsAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/BillAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/BillDetailAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/BillDetailsAppResponse.java delete mode 100644 server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/LastBillMemberAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/MemberAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/MemberDepositAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/MemberSaveAppResponse.java delete mode 100644 server/src/main/java/server/haengdong/application/response/MembersAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/MembersDepositAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/MembersSaveAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/StepAppResponse.java delete mode 100644 server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java delete mode 100644 server/src/main/java/server/haengdong/domain/action/BillActionRepository.java delete mode 100644 server/src/main/java/server/haengdong/domain/action/CurrentMembers.java delete mode 100644 server/src/main/java/server/haengdong/domain/action/MemberAction.java delete mode 100644 server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java delete mode 100644 server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java delete mode 100644 server/src/main/java/server/haengdong/domain/action/MemberBillReport.java delete mode 100644 server/src/main/java/server/haengdong/domain/action/Sequence.java rename server/src/main/java/server/haengdong/domain/{action/BillAction.java => bill/Bill.java} (51%) rename server/src/main/java/server/haengdong/domain/{action/BillActionDetail.java => bill/BillDetail.java} (56%) create mode 100644 server/src/main/java/server/haengdong/domain/bill/BillDetailRepository.java create mode 100644 server/src/main/java/server/haengdong/domain/bill/BillRepository.java create mode 100644 server/src/main/java/server/haengdong/domain/event/Bank.java create mode 100644 server/src/main/java/server/haengdong/domain/event/EventImage.java create mode 100644 server/src/main/java/server/haengdong/domain/member/Member.java create mode 100644 server/src/main/java/server/haengdong/domain/member/MemberBillReport.java create mode 100644 server/src/main/java/server/haengdong/domain/member/MemberRepository.java create mode 100644 server/src/main/java/server/haengdong/domain/step/Step.java create mode 100644 server/src/main/java/server/haengdong/domain/step/Steps.java delete mode 100644 server/src/main/java/server/haengdong/presentation/BillActionDetailController.java create mode 100644 server/src/main/java/server/haengdong/presentation/BillController.java rename server/src/main/java/server/haengdong/presentation/{MemberActionController.java => MemberController.java} (51%) delete mode 100644 server/src/main/java/server/haengdong/presentation/admin/AdminBillActionController.java create mode 100644 server/src/main/java/server/haengdong/presentation/admin/AdminBillController.java delete mode 100644 server/src/main/java/server/haengdong/presentation/admin/AdminMemberActionController.java create mode 100644 server/src/main/java/server/haengdong/presentation/admin/AdminMemberController.java delete mode 100644 server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java delete mode 100644 server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java delete mode 100644 server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/BillDetailUpdateRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/BillDetailsUpdateRequest.java rename server/src/main/java/server/haengdong/presentation/request/{BillActionUpdateRequest.java => BillSaveRequest.java} (50%) rename server/src/main/java/server/haengdong/presentation/request/{BillActionSaveRequest.java => BillUpdateRequest.java} (63%) create mode 100644 server/src/main/java/server/haengdong/presentation/request/EventUpdateRequest.java delete mode 100644 server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/MemberSaveRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/MemberUpdateRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/MembersSaveRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/MembersUpdateRequest.java delete mode 100644 server/src/main/java/server/haengdong/presentation/response/ActionResponse.java delete mode 100644 server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java delete mode 100644 server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java delete mode 100644 server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java delete mode 100644 server/src/main/java/server/haengdong/presentation/response/BillActionDetailsResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/BillDetailResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/BillDetailsResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/BillResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/MemberDepositResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/MemberResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/MemberSaveResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/MembersSaveResponse.java delete mode 100644 server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java delete mode 100644 server/src/test/java/server/haengdong/application/BillActionServiceTest.java create mode 100644 server/src/test/java/server/haengdong/application/BillServiceTest.java delete mode 100644 server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java delete mode 100644 server/src/test/java/server/haengdong/application/MemberActionServiceTest.java create mode 100644 server/src/test/java/server/haengdong/application/MemberServiceTest.java rename server/src/test/java/server/haengdong/docs/{AdminBillActionControllerDocsTest.java => AdminBillControllerDocsTest.java} (60%) delete mode 100644 server/src/test/java/server/haengdong/docs/AdminMemberActionControllerDocsTest.java create mode 100644 server/src/test/java/server/haengdong/docs/AdminMemberControllerDocsTest.java delete mode 100644 server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java create mode 100644 server/src/test/java/server/haengdong/docs/BillControllerDocsTest.java delete mode 100644 server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java create mode 100644 server/src/test/java/server/haengdong/docs/MemberControllerDocsTest.java delete mode 100644 server/src/test/java/server/haengdong/domain/action/BillActionTest.java delete mode 100644 server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java delete mode 100644 server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java delete mode 100644 server/src/test/java/server/haengdong/domain/action/SequenceTest.java create mode 100644 server/src/test/java/server/haengdong/domain/bill/BillTest.java create mode 100644 server/src/test/java/server/haengdong/domain/member/MemberBillReportTest.java create mode 100644 server/src/test/java/server/haengdong/domain/step/StepTest.java create mode 100644 server/src/test/java/server/haengdong/domain/step/StepsTest.java delete mode 100644 server/src/test/java/server/haengdong/presentation/ActionControllerTest.java delete mode 100644 server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/BillControllerTest.java delete mode 100644 server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/MemberControllerTest.java rename server/src/test/java/server/haengdong/presentation/admin/{AdminBillActionControllerTest.java => AdminBillControllerTest.java} (58%) delete mode 100644 server/src/test/java/server/haengdong/presentation/admin/AdminMemberActionControllerTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/admin/AdminMemberControllerTest.java delete mode 100644 server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java diff --git a/server/src/docs/asciidoc/billAction.adoc b/server/src/docs/asciidoc/bill.adoc similarity index 77% rename from server/src/docs/asciidoc/billAction.adoc rename to server/src/docs/asciidoc/bill.adoc index dfd7e26db..db77542aa 100644 --- a/server/src/docs/asciidoc/billAction.adoc +++ b/server/src/docs/asciidoc/bill.adoc @@ -1,8 +1,8 @@ -== 지출 액션 +== 지출 -=== 지출 액션 생성 +=== 지출 생성 -operation::createBillActions[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] +operation::createBills[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] ==== [.red]#Exceptions# @@ -18,11 +18,11 @@ operation::createBillActions[snippets="path-parameters,http-request,request-body "message":"지출 내역은 비어 있으면 안됩니다." }, { - "code":"BILL_ACTION_TITLE_INVALID", + "code":"BILL_TITLE_INVALID", "message":"앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다." }, { - "code":"BILL_ACTION_PRICE_INVALID", + "code":"BILL_PRICE_INVALID", "message":"지출 금액은 10,000,000 이하의 자연수여야 합니다." }, { @@ -44,9 +44,9 @@ operation::createBillActions[snippets="path-parameters,http-request,request-body ] ---- -=== 지출 액션 수정 +=== 지출 수정 -operation::updateBillAction[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] +operation::updateBill[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] ==== [.red]#Exceptions# @@ -62,11 +62,11 @@ operation::updateBillAction[snippets="path-parameters,http-request,request-body, "message":"지출 금액은 공백일 수 없습니다." }, { - "code":"BILL_ACTION_TITLE_INVALID", + "code":"BILL_TITLE_INVALID", "message":"앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다." }, { - "code":"BILL_ACTION_PRICE_INVALID", + "code":"BILL_PRICE_INVALID", "message":"지출 금액은 %,d 이하의 자연수여야 합니다." }, { @@ -74,7 +74,7 @@ operation::updateBillAction[snippets="path-parameters,http-request,request-body, "message":"존재하지 않는 행사입니다." }, { - "code":"BILL_ACTION_NOT_FOUND", + "code":"BILL_NOT_FOUND", "message":"존재하지 않는 지출 액션입니다." }, { @@ -92,9 +92,9 @@ operation::updateBillAction[snippets="path-parameters,http-request,request-body, ] ---- -=== 지출 액션 삭제 +=== 지출 삭제 -operation::deleteBillAction[snippets="path-parameters,http-request,http-response,request-cookies"] +operation::deleteBill[snippets="path-parameters,http-request,http-response,request-cookies"] ==== [.red]#Exceptions# diff --git a/server/src/docs/asciidoc/billActionDetail.adoc b/server/src/docs/asciidoc/billDetail.adoc similarity index 78% rename from server/src/docs/asciidoc/billActionDetail.adoc rename to server/src/docs/asciidoc/billDetail.adoc index a8f19f21b..9c9cf7ff5 100644 --- a/server/src/docs/asciidoc/billActionDetail.adoc +++ b/server/src/docs/asciidoc/billDetail.adoc @@ -2,7 +2,7 @@ === 지출 상세 조회 -operation::findBillActionDetailsTest[snippets="path-parameters,http-request,http-response,request-cookies"] +operation::findBillDetails[snippets="path-parameters,http-request,http-response,request-cookies"] ==== [.red]#Exceptions# @@ -14,11 +14,11 @@ operation::findBillActionDetailsTest[snippets="path-parameters,http-request,http "message": "존재하지 않는 행사입니다." }, { - "code": "BILL_ACTION_NOT_FOUND", + "code": "BILL_NOT_FOUND", "message": "존재하지 않는 지출 액션입니다." }, { - "code": "BILL_ACTION_DETAIL_NOT_FOUND", + "code": "BILL_DETAIL_NOT_FOUND", "message": "존재하지 않는 참여자 지출입니다." }, { @@ -42,7 +42,7 @@ operation::findBillActionDetailsTest[snippets="path-parameters,http-request,http === 지출 상세 수정 -operation::updateBillActionDetailsTest[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] +operation::updateBillDetails[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] ==== [.red]#Exceptions# @@ -62,15 +62,15 @@ operation::updateBillActionDetailsTest[snippets="path-parameters,http-request,re "message": "존재하지 않는 행사입니다." }, { - "code": "BILL_ACTION_NOT_FOUND", + "code": "BILL_NOT_FOUND", "message": "존재하지 않는 지출 액션입니다." }, { - "code": "BILL_ACTION_DETAIL_NOT_FOUND", + "code": "BILL_DETAIL_NOT_FOUND", "message": "존재하지 않는 참여자 지출입니다." }, { - "code": "BILL_ACTION_PRICE_NOT_MATCHED", + "code": "BILL_PRICE_NOT_MATCHED", "message": "지출 총액이 일치하지 않습니다." }, { diff --git a/server/src/docs/asciidoc/event.adoc b/server/src/docs/asciidoc/event.adoc index 72511b91b..10b165282 100644 --- a/server/src/docs/asciidoc/event.adoc +++ b/server/src/docs/asciidoc/event.adoc @@ -68,7 +68,7 @@ operation::getEvent[snippets="path-parameters,http-request,response-body,respons === 행사 전체 참여자 목록 조회 -operation::findAllEventMember[snippets="path-parameters,http-request,response-body,response-fields,http-response,response-fields"] +operation::findAllMembers[snippets="path-parameters,http-request,response-body,response-fields,http-response,response-fields"] ==== [.red]#Exceptions# @@ -82,9 +82,9 @@ operation::findAllEventMember[snippets="path-parameters,http-request,response-bo ] ---- -=== 행사 전체 액션 이력 조회 +=== 행사 전체 지출 이력 조회 -operation::findActions[snippets="path-parameters,http-request,http-response,response-fields"] +operation::findBills[snippets="path-parameters,http-request,http-response,response-fields"] ==== [.red]#Exceptions# @@ -98,9 +98,9 @@ operation::findActions[snippets="path-parameters,http-request,http-response,resp ] ---- -=== 행사 참여자 이름 변경 +=== 행사 참여자 정보 변경 -operation::updateEventMemberName[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] +operation::updateMembers[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] ==== [.red]#Exceptions# [source,json,options="nowrap"] @@ -146,9 +146,9 @@ operation::updateEventMemberName[snippets="path-parameters,http-request,request- ] ---- -=== 행사 참여자 삭제 (특정 참여자의 모든 참여자 액션 삭제) +=== 행사 참여자 삭제 -operation::deleteAllMemberActionByName[snippets="path-parameters,http-request,http-response,request-cookies"] +operation::deleteMember[snippets="path-parameters,http-request,http-response,request-cookies"] ==== [.red]#Exceptions# [source,json,options="nowrap"] diff --git a/server/src/docs/asciidoc/index.adoc b/server/src/docs/asciidoc/index.adoc index 8e1bcd2d0..4dcc2dc26 100644 --- a/server/src/docs/asciidoc/index.adoc +++ b/server/src/docs/asciidoc/index.adoc @@ -10,6 +10,6 @@ endif::[] include::{docdir}/event.adoc[] include::{docdir}/memberBillReport.adoc[] -include::{docdir}/memberAction.adoc[] -include::{docdir}/billAction.adoc[] -include::{docdir}/billActionDetail.adoc[] +include::{docdir}/member.adoc[] +include::{docdir}/bill.adoc[] +include::{docdir}/billDetail.adoc[] diff --git a/server/src/docs/asciidoc/member.adoc b/server/src/docs/asciidoc/member.adoc new file mode 100644 index 000000000..230db1906 --- /dev/null +++ b/server/src/docs/asciidoc/member.adoc @@ -0,0 +1,152 @@ +== 참여자 + +=== 행사 참여자 추가(멤버 추가) + +operation::saveMembers[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"REQUEST_EMPTY", + "message":"멤버 목록은 공백일 수 없습니다." + }, + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"MEMBER_ALREADY_EXIST", + "message":"현재 참여하고 있는 인원이 존재합니다." + }, + { + "code":"MEMBER_NAME_DUPLICATE", + "message":"중복된 이름이 존재합니다. 입력된 이름: [이상, 이상, 감자, 백호]" + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"만료된 토큰입니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + }, + { + "code":"FORBIDDEN", + "message":"접근할 수 없는 행사입니다." + } +] +---- + +=== 행사 참여 인원에서 삭제(멤버 삭제) + +operation::deleteMember[snippets="path-parameters,http-request,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"만료된 토큰입니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + }, + { + "code":"FORBIDDEN", + "message":"접근할 수 없는 행사입니다." + } +] +---- + +=== 멤버 정보 수정 + +operation::updateMembers[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code": "REQUEST_EMPTY", + "message": "멤버 ID는 공백일 수 없습니다." + }, + { + "code": "REQUEST_EMPTY", + "message": "입금 여부는 공백일 수 없습니다." + }, + { + "code": "REQUEST_EMPTY", + "message": "멤버 이름은 공백일 수 없습니다." + }, + { + "code": "MEMBER_NAME_LENGTH_INVALID", + "message": "멤버 이름은 1자 이상 4자 이하만 입력 가능합니다." + }, + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code": "MEMBER_NOT_FOUND", + "message": "존재하지 않는 참여자입니다." + }, + { + "code": "MEMBER_NAME_DUPLICATE", + "message": "중복된 행사 참여 인원 이름이 존재합니다." + }, + { + "code": "MEMBER_NAME_CHANGE_DUPLICATE", + "message": "중복된 참여 인원 이름 변경 요청이 존재합니다." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"만료된 토큰입니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + }, + { + "code":"FORBIDDEN", + "message":"접근할 수 없는 행사입니다." + } +] +---- + +=== 현재 행사에 참여 중인 (탈주 가능한) 참여자 목록 조회 + +operation::getCurrentMembers[snippets="path-parameters,http-request,http-response,response-fields"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + } +] +---- diff --git a/server/src/docs/asciidoc/memberAction.adoc b/server/src/docs/asciidoc/memberAction.adoc deleted file mode 100644 index 897102c8d..000000000 --- a/server/src/docs/asciidoc/memberAction.adoc +++ /dev/null @@ -1,100 +0,0 @@ -== 참여자 액션 - -=== 참여자 액션 생성 - -operation::createMemberAction[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] - -==== [.red]#Exceptions# - -[source,json,options="nowrap"] ----- -[ - { - "code":"REQUEST_EMPTY", - "message":"멤버 액션은 공백일 수 없습니다." - }, - { - "code":"EVENT_NOT_FOUND", - "message":"존재하지 않는 행사입니다." - }, - { - "code":"MEMBER_ACTION_STATUS_INVALID", - "message":"멤버 액션은 IN, OUT만 가능합니다. 입력한 멤버 액션: I_N" - }, - { - "code":"MEMBER_ALREADY_EXIST", - "message":"현재 참여하고 있는 인원이 존재합니다." - }, - { - "code":"MEMBER_NOT_EXIST", - "message":"현재 참여하고 있지 않는 인원이 존재합니다." - }, - { - "code":"MEMBER_NAME_DUPLICATE", - "message":"중복된 이름이 존재합니다. 입력된 이름: 이상, 이상, 감자, 백호" - }, - { - "code":"TOKEN_NOT_FOUND", - "message":"토큰이 존재하지 않습니다." - }, - { - "code":"TOKEN_EXPIRED", - "message":"토큰이 존재하지 않습니다." - }, - { - "code":"TOKEN_INVALID", - "message":"유효하지 않은 토큰입니다." - } -] ----- - -=== 현재 행사에 참여 중인 (탈주 가능한) 참여자 목록 조회 - -operation::getCurrentMembers[snippets="path-parameters,http-request,http-response,response-fields"] -==== [.red]#Exceptions# - -[source,json,options="nowrap"] ----- -[ - { - "code":"EVENT_NOT_FOUND", - "message":"존재하지 않는 행사입니다." - } -] ----- - -=== 참여자 액션 삭제 - -operation::deleteMemberAction[snippets="path-parameters,http-request,http-response,request-cookies"] - -==== [.red]#Exceptions# - -[source,json,options="nowrap"] ----- -[ - { - "code":"EVENT_NOT_FOUND", - "message":"존재하지 않는 행사입니다." - }, - { - "code":"ACTION_NOT_FOUND", - "message":"존재하지 않는 액션입니다." - }, - { - "code":"MEMBER_ACTION_NOT_FOUND", - "message":"존재하지 않는 멤버 액션입니다." - }, - { - "code":"TOKEN_NOT_FOUND", - "message":"토큰이 존재하지 않습니다." - }, - { - "code":"TOKEN_EXPIRED", - "message":"토큰이 존재하지 않습니다." - }, - { - "code":"TOKEN_INVALID", - "message":"유효하지 않은 토큰입니다." - } -] ----- diff --git a/server/src/main/java/server/haengdong/application/BillActionDetailService.java b/server/src/main/java/server/haengdong/application/BillActionDetailService.java deleted file mode 100644 index a4372c62d..000000000 --- a/server/src/main/java/server/haengdong/application/BillActionDetailService.java +++ /dev/null @@ -1,78 +0,0 @@ -package server.haengdong.application; - -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import server.haengdong.application.request.BillActionDetailUpdateAppRequest; -import server.haengdong.application.request.BillActionDetailsUpdateAppRequest; -import server.haengdong.application.response.BillActionDetailsAppResponse; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.BillActionDetail; -import server.haengdong.domain.action.BillActionRepository; -import server.haengdong.domain.event.Event; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -@RequiredArgsConstructor -@Transactional(readOnly = true) -@Service -public class BillActionDetailService { - - private final BillActionRepository billActionRepository; - - public BillActionDetailsAppResponse findBillActionDetails(String token, Long billActionId) { - BillAction billAction = billActionRepository.findById(billActionId) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); - validateToken(token, billAction); - - List<BillActionDetail> billActionDetails = billAction.getBillActionDetails(); - return BillActionDetailsAppResponse.of(billActionDetails); - } - - @Transactional - public void updateBillActionDetails(String token, Long billActionId, BillActionDetailsUpdateAppRequest request) { - BillAction billAction = billActionRepository.findById(billActionId) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); - - List<BillActionDetailUpdateAppRequest> billActionDetailUpdateAppRequests = request.billActionDetailUpdateAppRequests(); - - validateToken(token, billAction); - validateTotalPrice(billActionDetailUpdateAppRequests, billAction); - - List<BillActionDetail> billActionDetails = billAction.getBillActionDetails(); - - for (BillActionDetailUpdateAppRequest updateRequest : billActionDetailUpdateAppRequests) { - BillActionDetail detailToUpdate = billActionDetails.stream() - .filter(detail -> detail.isSameName(updateRequest.name())) - .findFirst() - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_DETAIL_NOT_FOUND)); - - detailToUpdate.updatePrice(updateRequest.price()); - detailToUpdate.updateIsFixed(updateRequest.isFixed()); - } - } - - private void validateToken(String token, BillAction billAction) { - Event event = billAction.getEvent(); - if (event.isTokenMismatch(token)) { - throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND); - } - } - - private void validateTotalPrice( - List<BillActionDetailUpdateAppRequest> billActionDetailUpdateAppRequests, - BillAction billAction - ) { - Long requestsPriceSum = calculateUpdatePriceSum(billActionDetailUpdateAppRequests); - if (!billAction.isSamePrice(requestsPriceSum)) { - throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_PRICE_NOT_MATCHED); - } - } - - private Long calculateUpdatePriceSum(List<BillActionDetailUpdateAppRequest> billActionDetailUpdateAppRequests) { - return billActionDetailUpdateAppRequests.stream() - .map(BillActionDetailUpdateAppRequest::price) - .reduce(0L, Long::sum); - } -} diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java deleted file mode 100644 index 9453a2d5f..000000000 --- a/server/src/main/java/server/haengdong/application/BillActionService.java +++ /dev/null @@ -1,85 +0,0 @@ -package server.haengdong.application; - -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import server.haengdong.application.request.BillActionAppRequest; -import server.haengdong.application.request.BillActionUpdateAppRequest; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.BillActionRepository; -import server.haengdong.domain.action.CurrentMembers; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionRepository; -import server.haengdong.domain.action.Sequence; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -@RequiredArgsConstructor -@Transactional(readOnly = true) -@Service -public class BillActionService { - - private final BillActionRepository billActionRepository; - private final MemberActionRepository memberActionRepository; - private final EventRepository eventRepository; - - @Transactional - public void saveAllBillAction(String eventToken, List<BillActionAppRequest> requests) { - Event event = getEvent(eventToken); - Sequence sequence = createStartSequence(event); - List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event); - CurrentMembers currentMembers = CurrentMembers.of(findMemberActions); - - for (BillActionAppRequest request : requests) { - BillAction billAction = request.toBillAction(event, sequence, currentMembers); - billActionRepository.save(billAction); - sequence = sequence.next(); - } - } - - private Sequence createStartSequence(Event event) { - Sequence memberActionSequence = memberActionRepository.findLastByEvent(event) - .map(MemberAction::getSequence) - .orElseGet(Sequence::createFirst); - Sequence billActionSequence = billActionRepository.findLastByEvent(event) - .map(BillAction::getSequence) - .orElseGet(Sequence::createFirst); - return Sequence.getGreater(memberActionSequence, billActionSequence).next(); - } - - @Transactional - public void updateBillAction(String token, Long billActionId, BillActionUpdateAppRequest request) { - BillAction billAction = getBillAction(billActionId); - - validateToken(token, billAction); - - billAction.update(request.title(), request.price()); - } - - private void validateToken(String token, BillAction billAction) { - Event event = billAction.getEvent(); - if (event.isTokenMismatch(token)) { - throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND); - } - } - - @Transactional - public void deleteBillAction(String token, Long billActionId) { - BillAction billAction = getBillAction(billActionId); - validateToken(token, billAction); - billActionRepository.deleteById(billActionId); - } - - private Event getEvent(String eventToken) { - return eventRepository.findByToken(eventToken) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); - } - - private BillAction getBillAction(Long billActionId) { - return billActionRepository.findById(billActionId) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); - } -} diff --git a/server/src/main/java/server/haengdong/application/BillService.java b/server/src/main/java/server/haengdong/application/BillService.java new file mode 100644 index 000000000..407914d29 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/BillService.java @@ -0,0 +1,155 @@ +package server.haengdong.application; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.BillAppRequest; +import server.haengdong.application.request.BillDetailUpdateAppRequest; +import server.haengdong.application.request.BillDetailsUpdateAppRequest; +import server.haengdong.application.request.BillUpdateAppRequest; +import server.haengdong.application.response.BillDetailsAppResponse; +import server.haengdong.application.response.StepAppResponse; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.bill.BillDetail; +import server.haengdong.domain.bill.BillRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.domain.member.Member; +import server.haengdong.domain.member.MemberRepository; +import server.haengdong.domain.step.Steps; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class BillService { + + private final BillRepository billRepository; + private final EventRepository eventRepository; + private final MemberRepository memberRepository; + + @Transactional + public void saveBill(String eventToken, BillAppRequest request) { + Event event = getEvent(eventToken); + List<Long> memberIds = request.memberIds(); + List<Member> members = memberIds.stream() + .map(this::findMember) + .toList(); + + Bill bill = request.toBill(event, members); + billRepository.save(bill); + } + + private Member findMember(Long memberId) { + return memberRepository.findById(memberId) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_NOT_FOUND)); + } + + public List<StepAppResponse> findSteps(String token) { + Event event = getEvent(token); + List<Bill> bills = billRepository.findAllByEvent(event); + + return createStepAppResponses(bills); + } + + private List<StepAppResponse> createStepAppResponses(List<Bill> bills) { + Steps steps = Steps.of(bills); + return steps.getSteps().stream() + .map(StepAppResponse::of) + .toList(); + } + + @Transactional + public void updateBill(String token, Long billId, BillUpdateAppRequest request) { + Bill bill = getBill(billId); + + validateToken(token, bill); + + bill.update(request.title(), request.price()); + } + + private void validateToken(String token, Bill bill) { + Event event = bill.getEvent(); + if (event.isTokenMismatch(token)) { + throw new HaengdongException(HaengdongErrorCode.BILL_NOT_FOUND); + } + } + + @Transactional + public void deleteBill(String token, Long billId) { + Bill bill = getBill(billId); + validateToken(token, bill); + billRepository.deleteById(billId); + } + + public BillDetailsAppResponse findBillDetails(String token, Long billId) { + Bill bill = billRepository.findById(billId) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_NOT_FOUND)); + validateToken(token, bill); + + List<BillDetail> billDetails = bill.getBillDetails(); + return BillDetailsAppResponse.of(billDetails); + } + + @Transactional + public void updateBillDetails(String token, Long billId, BillDetailsUpdateAppRequest request) { + Bill bill = billRepository.findById(billId) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_NOT_FOUND)); + + List<BillDetailUpdateAppRequest> billDetailUpdateAppRequests = request.billDetailUpdateAppRequests(); + + validateToken(token, bill); + validateBillDetailSize(billDetailUpdateAppRequests, bill); + validateTotalPrice(billDetailUpdateAppRequests, bill); + + List<BillDetail> billDetails = bill.getBillDetails(); + + for (BillDetailUpdateAppRequest updateRequest : billDetailUpdateAppRequests) { + BillDetail detailToUpdate = billDetails.stream() + .filter(detail -> detail.isSameId(updateRequest.id())) + .findFirst() + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_DETAIL_NOT_FOUND)); + + detailToUpdate.updatePrice(updateRequest.price()); + detailToUpdate.updateIsFixed(updateRequest.isFixed()); + } + } + + private void validateBillDetailSize(List<BillDetailUpdateAppRequest> requests, Bill bill) { + List<Long> ids = requests.stream() + .map(BillDetailUpdateAppRequest::id) + .distinct() + .toList(); + if (bill.getBillDetails().size() != ids.size()) { + throw new HaengdongException(HaengdongErrorCode.BILL_DETAIL_NOT_FOUND); + } + } + + private void validateTotalPrice( + List<BillDetailUpdateAppRequest> billDetailUpdateAppRequests, + Bill bill + ) { + Long requestsPriceSum = calculateUpdatePriceSum(billDetailUpdateAppRequests); + if (!bill.isSamePrice(requestsPriceSum)) { + throw new HaengdongException(HaengdongErrorCode.BILL_PRICE_NOT_MATCHED); + } + } + + private Long calculateUpdatePriceSum(List<BillDetailUpdateAppRequest> billDetailUpdateAppRequests) { + return billDetailUpdateAppRequests.stream() + .map(BillDetailUpdateAppRequest::price) + .reduce(0L, Long::sum); + } + + private Event getEvent(String eventToken) { + return eventRepository.findByToken(eventToken) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + } + + private Bill getBill(Long billId) { + return billRepository.findById(billId) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_NOT_FOUND)); + } +} diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java index 106186af3..bb6d2b51f 100644 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -1,27 +1,20 @@ package server.haengdong.application; -import java.util.ArrayList; -import java.util.Comparator; import java.util.List; -import java.util.Set; +import java.util.Map.Entry; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import server.haengdong.application.request.EventAppRequest; import server.haengdong.application.request.EventLoginAppRequest; -import server.haengdong.application.request.MemberNameUpdateAppRequest; -import server.haengdong.application.request.MemberNamesUpdateAppRequest; -import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.request.EventUpdateAppRequest; import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; import server.haengdong.application.response.MemberBillReportAppResponse; -import server.haengdong.application.response.MembersAppResponse; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.BillActionDetailRepository; -import server.haengdong.domain.action.BillActionRepository; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionRepository; -import server.haengdong.domain.action.MemberBillReport; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.bill.BillRepository; +import server.haengdong.domain.member.Member; +import server.haengdong.domain.member.MemberBillReport; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.domain.event.EventTokenProvider; @@ -36,10 +29,7 @@ public class EventService { private final EventRepository eventRepository; private final EventTokenProvider eventTokenProvider; - private final BillActionRepository billActionRepository; - private final MemberActionRepository memberActionRepository; - private final BillActionDetailRepository billActionDetailRepository; - + private final BillRepository billRepository; @Transactional public EventAppResponse saveEvent(EventAppRequest request) { @@ -56,108 +46,6 @@ public EventDetailAppResponse findEvent(String token) { return EventDetailAppResponse.of(event); } - public List<ActionAppResponse> findActions(String token) { - Event event = getEvent(token); - - List<BillAction> billActions = billActionRepository.findByEvent(event).stream() - .sorted(Comparator.comparing(BillAction::getSequence)).toList(); - List<MemberAction> memberActions = memberActionRepository.findAllByEvent(event).stream() - .sorted(Comparator.comparing(MemberAction::getSequence)).toList(); - - return getActionAppResponses(billActions, memberActions); - } - - private List<ActionAppResponse> getActionAppResponses( - List<BillAction> billActions, - List<MemberAction> memberActions - ) { - int billActionIndex = 0; - int memberActionIndex = 0; - List<ActionAppResponse> actionAppResponses = new ArrayList<>(); - - while (billActionIndex < billActions.size() && memberActionIndex < memberActions.size()) { - BillAction billAction = billActions.get(billActionIndex); - MemberAction memberAction = memberActions.get(memberActionIndex); - if (billAction.getSequence().getValue() < memberAction.getSequence().getValue()) { - actionAppResponses.add(ActionAppResponse.of(billAction)); - billActionIndex++; - } else { - actionAppResponses.add(ActionAppResponse.of(memberAction)); - memberActionIndex++; - } - } - while (billActionIndex < billActions.size()) { - BillAction billAction = billActions.get(billActionIndex++); - actionAppResponses.add(ActionAppResponse.of(billAction)); - } - while (memberActionIndex < memberActions.size()) { - MemberAction memberAction = memberActions.get(memberActionIndex++); - actionAppResponses.add(ActionAppResponse.of(memberAction)); - } - - return actionAppResponses; - } - - public MembersAppResponse findAllMembers(String token) { - Event event = getEvent(token); - - List<String> memberNames = memberActionRepository.findAllUniqueMemberByEvent(event); - - return new MembersAppResponse(memberNames); - } - - @Transactional - public void updateMember(String token, MemberNamesUpdateAppRequest request) { - Event event = getEvent(token); - List<MemberNameUpdateAppRequest> members = request.members(); - - validateBeforeNames(members, event); - validateAfterNames(members, event); - - members.forEach(member -> updateMemberName(event, member.before(), member.after())); - } - - private void validateBeforeNames(List<MemberNameUpdateAppRequest> members, Event event) { - List<String> beforeNames = members.stream() - .map(MemberNameUpdateAppRequest::before) - .toList(); - if (beforeNames.size() != Set.copyOf(beforeNames).size()) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); - } - beforeNames.forEach(beforeName -> validateBeforeMemberNameExist(event, beforeName)); - } - - private void validateBeforeMemberNameExist(Event event, String beforeName) { - boolean isMemberNameExist = memberActionRepository.existsByEventAndMemberName(event, beforeName); - if (!isMemberNameExist) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NOT_EXIST); - } - } - - private void validateAfterNames(List<MemberNameUpdateAppRequest> members, Event event) { - List<String> afterNames = members.stream() - .map(MemberNameUpdateAppRequest::after) - .toList(); - if (afterNames.size() != Set.copyOf(afterNames).size()) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); - } - afterNames.forEach(afterName -> validateAfterMemberNameNotExist(event, afterName)); - } - - private void validateAfterMemberNameNotExist(Event event, String afterName) { - boolean isMemberNameExist = memberActionRepository.existsByEventAndMemberName(event, afterName); - if (isMemberNameExist) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); - } - } - - private void updateMemberName(Event event, String beforeName, String afterName) { - memberActionRepository.findAllByEventAndMemberName(event, beforeName) - .forEach(memberAction -> memberAction.updateMemberName(afterName)); - billActionDetailRepository.findAllByBillAction_EventAndMemberName(event, beforeName) - .forEach(billActionDetail -> billActionDetail.updateMemberName(afterName)); - } - public void validatePassword(EventLoginAppRequest request) throws HaengdongException { Event event = getEvent(request.token()); if (event.isPasswordMismatch(request.password())) { @@ -173,13 +61,35 @@ private Event getEvent(String token) { public List<MemberBillReportAppResponse> getMemberBillReports(String token) { Event event = eventRepository.findByToken(token) .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); - List<BillAction> billActions = billActionRepository.findByEvent(event); - List<MemberAction> memberActions = memberActionRepository.findAllByEvent(event); + List<Bill> bills = billRepository.findAllByEvent(event); - MemberBillReport memberBillReport = MemberBillReport.createByActions(billActions, memberActions); + MemberBillReport memberBillReport = MemberBillReport.createByBills(bills); return memberBillReport.getReports().entrySet().stream() - .map(entry -> new MemberBillReportAppResponse(entry.getKey(), entry.getValue())) + .map(this::createMemberBillReportResponse) .toList(); } + + private MemberBillReportAppResponse createMemberBillReportResponse(Entry<Member, Long> entry) { + Member member = entry.getKey(); + Long price = entry.getValue(); + + return new MemberBillReportAppResponse( + member.getId(), + member.getName(), + member.isDeposited(), + price + ); + } + + @Transactional + public void updateEvent(String token, EventUpdateAppRequest request) { + Event event = getEvent(token); + if (request.isEventNameExist()) { + event.rename(request.eventName()); + } + if (request.isAccountExist()) { + event.changeAccount(request.bankName(), request.accountNumber()); + } + } } diff --git a/server/src/main/java/server/haengdong/application/MemberActionFactory.java b/server/src/main/java/server/haengdong/application/MemberActionFactory.java deleted file mode 100644 index 97fa1038c..000000000 --- a/server/src/main/java/server/haengdong/application/MemberActionFactory.java +++ /dev/null @@ -1,60 +0,0 @@ -package server.haengdong.application; - -import java.util.ArrayList; -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; -import server.haengdong.application.request.MemberActionSaveAppRequest; -import server.haengdong.application.request.MemberActionsSaveAppRequest; -import server.haengdong.domain.action.CurrentMembers; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionStatus; -import server.haengdong.domain.action.Sequence; -import server.haengdong.domain.event.Event; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -@RequiredArgsConstructor -@Component -public class MemberActionFactory { - - public List<MemberAction> createMemberActions( - Event event, - MemberActionsSaveAppRequest request, - CurrentMembers currentMembers, - Sequence sequence - ) { - validateMemberNames(request); - validateActions(request, currentMembers); - - List<MemberAction> createdMemberActions = new ArrayList<>(); - List<MemberActionSaveAppRequest> actions = request.actions(); - for (MemberActionSaveAppRequest appRequest : actions) { - MemberAction memberAction = appRequest.toMemberAction(event, sequence); - createdMemberActions.add(memberAction); - sequence = sequence.next(); - } - - return createdMemberActions; - } - - private void validateMemberNames(MemberActionsSaveAppRequest request) { - List<String> memberNames = request.actions().stream() - .map(MemberActionSaveAppRequest::name) - .toList(); - - long uniqueCount = memberNames.stream().distinct().count(); - if (uniqueCount != memberNames.size()) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); - } - } - - private void validateActions(MemberActionsSaveAppRequest request, CurrentMembers currentMembers) { - List<MemberActionSaveAppRequest> actions = request.actions(); - - for (MemberActionSaveAppRequest action : actions) { - MemberActionStatus memberActionStatus = MemberActionStatus.of(action.status()); - currentMembers.validate(action.name(), memberActionStatus); - } - } -} diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java deleted file mode 100644 index 26186c08a..000000000 --- a/server/src/main/java/server/haengdong/application/MemberActionService.java +++ /dev/null @@ -1,100 +0,0 @@ -package server.haengdong.application; - -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import server.haengdong.application.request.MemberActionsSaveAppRequest; -import server.haengdong.application.response.CurrentMemberAppResponse; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.BillActionRepository; -import server.haengdong.domain.action.CurrentMembers; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionRepository; -import server.haengdong.domain.action.Sequence; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -@RequiredArgsConstructor -@Transactional(readOnly = true) -@Service -public class MemberActionService { - - private final MemberActionFactory memberActionFactory; - private final MemberActionRepository memberActionRepository; - private final EventRepository eventRepository; - private final BillActionRepository billActionRepository; - - @Transactional - public void saveMemberAction(String token, MemberActionsSaveAppRequest request) { - Event event = findEvent(token); - - List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event); - CurrentMembers currentMembers = CurrentMembers.of(findMemberActions); - Sequence sequence = createStartSequence(event); - List<MemberAction> memberActions = memberActionFactory.createMemberActions(event, request, currentMembers, - sequence); - memberActionRepository.saveAll(memberActions); - } - - private Sequence createStartSequence(Event event) { - Sequence memberActionSequence = memberActionRepository.findLastByEvent(event) - .map(MemberAction::getSequence) - .orElseGet(Sequence::createFirst); - Sequence billActionSequence = billActionRepository.findLastByEvent(event) - .map(BillAction::getSequence) - .orElseGet(Sequence::createFirst); - return Sequence.getGreater(memberActionSequence, billActionSequence).next(); - } - - public List<CurrentMemberAppResponse> getCurrentMembers(String token) { - Event event = findEvent(token); - List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event); - CurrentMembers currentMembers = CurrentMembers.of(findMemberActions); - - return currentMembers.getMembers() - .stream() - .map(CurrentMemberAppResponse::new) - .toList(); - } - - private Event findEvent(String token) { - return eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); - } - - @Transactional - public void deleteMember(String token, String memberName) { - Event event = eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); - - memberActionRepository.deleteAllByEventAndMemberName(event, memberName); - - List<BillAction> billActions = billActionRepository.findByEvent(event); - billActions.forEach(billAction -> resetBillAction(event, billAction)); - } - - @Transactional - public void deleteMemberAction(String token, Long id) { - Event event = eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); - MemberAction memberAction = memberActionRepository.findByIdAndEvent(id, event); - - memberActionRepository.deleteAllByMemberNameAndMinSequence(memberAction.getMemberName(), - memberAction.getSequence().getValue()); - - List<BillAction> billActions = billActionRepository.findByEventAndGreaterThanSequence(event, - memberAction.getSequence().getValue()); - billActions.forEach(billAction -> resetBillAction(event, billAction)); - } - - private void resetBillAction(Event event, BillAction billAction) { - List<MemberAction> memberActions = memberActionRepository.findByEventAndSequence(event, - billAction.getSequence().getValue()); - CurrentMembers currentMembers = CurrentMembers.of(memberActions); - - billAction.resetBillActionDetails(currentMembers); - } -} diff --git a/server/src/main/java/server/haengdong/application/MemberService.java b/server/src/main/java/server/haengdong/application/MemberService.java new file mode 100644 index 000000000..d54d3b3a0 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/MemberService.java @@ -0,0 +1,171 @@ +package server.haengdong.application; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.MemberSaveAppRequest; +import server.haengdong.application.request.MemberUpdateAppRequest; +import server.haengdong.application.request.MembersSaveAppRequest; +import server.haengdong.application.request.MembersUpdateAppRequest; +import server.haengdong.application.response.MemberAppResponse; +import server.haengdong.application.response.MembersDepositAppResponse; +import server.haengdong.application.response.MembersSaveAppResponse; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.bill.BillDetailRepository; +import server.haengdong.domain.bill.BillRepository; +import server.haengdong.domain.member.Member; +import server.haengdong.domain.member.MemberRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class MemberService { + + private final MemberRepository memberRepository; + private final EventRepository eventRepository; + private final BillRepository billRepository; + private final BillDetailRepository billDetailRepository; + + public MembersSaveAppResponse saveMembers(String token, MembersSaveAppRequest request) { + Event event = getEvent(token); + List<String> memberNames = request.members().stream() + .map(MemberSaveAppRequest::name) + .toList(); + + validateMemberSave(memberNames, event); + + List<Member> members = memberNames.stream() + .map(name -> new Member(event, name)) + .toList(); + + List<Member> savedMembers = memberRepository.saveAll(members); + return MembersSaveAppResponse.of(savedMembers); + } + + public List<MemberAppResponse> getCurrentMembers(String token) { + Event event = getEvent(token); + + return billRepository.findFirstByEventOrderByIdDesc(event) + .map(Bill::getMembers) + .orElseGet(() -> memberRepository.findAllByEvent(event)) + .stream() + .map(MemberAppResponse::of) + .toList(); + } + + private void validateMemberSave(List<String> memberNames, Event event) { + if (memberNamesDuplicated(memberNames)) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE, + "중복된 이름이 존재합니다. 입력된 이름: " + memberNames); + } + if (memberRepository.findAllByEvent(event).stream() + .anyMatch(member -> memberNames.contains(member.getName()))) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_ALREADY_EXIST); + } + } + + public MembersDepositAppResponse findAllMembers(String token) { + Event event = getEvent(token); + + List<Member> members = memberRepository.findAllByEvent(event); + + return MembersDepositAppResponse.of(members); + } + + @Transactional + public void updateMembers(String token, MembersUpdateAppRequest request) { + Event event = getEvent(token); + validateMemberUpdate(request); + + List<Member> updatedMembers = request.members().stream() + .map(memberRequest -> memberRequest.toMember(event)) + .toList(); + List<Member> eventMembers = memberRepository.findAllByEvent(event); + + validateUpdatedMembersExist(eventMembers, updatedMembers); + validateUpdatedNamesUnique(eventMembers, updatedMembers); + memberRepository.saveAll(updatedMembers); + } + + private Event getEvent(String token) { + return eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + } + + private void validateMemberUpdate(MembersUpdateAppRequest request) { + validateChangedNameUnique(request.members()); + validateMemberUnique(request.members()); + } + + private void validateChangedNameUnique(List<MemberUpdateAppRequest> members) { + List<String> memberNames = members.stream() + .map(MemberUpdateAppRequest::name) + .toList(); + if (memberNamesDuplicated(memberNames)) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); + } + } + + private boolean memberNamesDuplicated(List<String> memberNames) { + return memberNames.size() != Set.copyOf(memberNames).size(); + } + + private void validateMemberUnique(List<MemberUpdateAppRequest> members) { + List<Long> memberIds = members.stream() + .map(MemberUpdateAppRequest::id) + .distinct() + .toList(); + if (members.size() != memberIds.size()) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); + } + } + + private void validateUpdatedMembersExist(List<Member> eventMembers, List<Member> updatedMembers) { + Set<Member> members = new HashSet<>(eventMembers); + + if (!members.containsAll(updatedMembers)) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NOT_FOUND); + } + } + + private void validateUpdatedNamesUnique(List<Member> eventMembers, List<Member> updatedMembers) { + Set<String> eventMemberNames = eventMembers.stream() + .map(Member::getName) + .collect(Collectors.toSet()); + + boolean memberNameDuplicated = updatedMembers.stream() + .map(Member::getName) + .anyMatch(eventMemberNames::contains); + + if (memberNameDuplicated) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); + } + } + + @Transactional + public void deleteMember(String token, Long memberId) { + memberRepository.findById(memberId) + .ifPresent(member -> deleteMember(token, member)); + } + + private void deleteMember(String token, Member member) { + Event event = member.getEvent(); + if (event.isTokenMismatch(token)) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NOT_FOUND); + } + + billRepository.findAllByEvent(event).stream() + .filter(bill -> bill.containMember(member)) + .forEach(bill -> bill.removeMemberBillDetail(member)); + billDetailRepository.deleteAllByMember(member); + memberRepository.delete(member); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java deleted file mode 100644 index c702fd0be..000000000 --- a/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java +++ /dev/null @@ -1,16 +0,0 @@ -package server.haengdong.application.request; - -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.CurrentMembers; -import server.haengdong.domain.action.Sequence; -import server.haengdong.domain.event.Event; - -public record BillActionAppRequest( - String title, - Long price -) { - - public BillAction toBillAction(Event event, Sequence sequence, CurrentMembers currentMembers) { - return BillAction.create(event, sequence, title, price, currentMembers); - } -} diff --git a/server/src/main/java/server/haengdong/application/request/BillActionDetailsUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionDetailsUpdateAppRequest.java deleted file mode 100644 index 1fe19798e..000000000 --- a/server/src/main/java/server/haengdong/application/request/BillActionDetailsUpdateAppRequest.java +++ /dev/null @@ -1,8 +0,0 @@ -package server.haengdong.application.request; - -import java.util.List; - -public record BillActionDetailsUpdateAppRequest( - List<BillActionDetailUpdateAppRequest> billActionDetailUpdateAppRequests -) { -} diff --git a/server/src/main/java/server/haengdong/application/request/BillAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillAppRequest.java new file mode 100644 index 000000000..8eb945263 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/BillAppRequest.java @@ -0,0 +1,17 @@ +package server.haengdong.application.request; + +import java.util.List; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.member.Member; +import server.haengdong.domain.event.Event; + +public record BillAppRequest( + String title, + Long price, + List<Long> memberIds +) { + + public Bill toBill(Event event, List<Member> members) { + return Bill.create(event, title, price, members); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillDetailUpdateAppRequest.java similarity index 58% rename from server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java rename to server/src/main/java/server/haengdong/application/request/BillDetailUpdateAppRequest.java index e514aee81..4e66b9215 100644 --- a/server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java +++ b/server/src/main/java/server/haengdong/application/request/BillDetailUpdateAppRequest.java @@ -1,7 +1,7 @@ package server.haengdong.application.request; -public record BillActionDetailUpdateAppRequest( - String name, +public record BillDetailUpdateAppRequest( + Long id, Long price, boolean isFixed ) { diff --git a/server/src/main/java/server/haengdong/application/request/BillDetailsUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillDetailsUpdateAppRequest.java new file mode 100644 index 000000000..7a6477e08 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/BillDetailsUpdateAppRequest.java @@ -0,0 +1,8 @@ +package server.haengdong.application.request; + +import java.util.List; + +public record BillDetailsUpdateAppRequest( + List<BillDetailUpdateAppRequest> billDetailUpdateAppRequests +) { +} diff --git a/server/src/main/java/server/haengdong/application/request/BillActionUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillUpdateAppRequest.java similarity index 69% rename from server/src/main/java/server/haengdong/application/request/BillActionUpdateAppRequest.java rename to server/src/main/java/server/haengdong/application/request/BillUpdateAppRequest.java index a90e3dd42..aa09f2351 100644 --- a/server/src/main/java/server/haengdong/application/request/BillActionUpdateAppRequest.java +++ b/server/src/main/java/server/haengdong/application/request/BillUpdateAppRequest.java @@ -1,6 +1,6 @@ package server.haengdong.application.request; -public record BillActionUpdateAppRequest( +public record BillUpdateAppRequest( String title, Long price ) { diff --git a/server/src/main/java/server/haengdong/application/request/EventUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/EventUpdateAppRequest.java new file mode 100644 index 000000000..13bffccc1 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/EventUpdateAppRequest.java @@ -0,0 +1,17 @@ +package server.haengdong.application.request; + +public record EventUpdateAppRequest( + String eventName, + String bankName, + String accountNumber +) { + + public boolean isEventNameExist() { + return eventName != null && !eventName.trim().isEmpty(); + } + + public boolean isAccountExist() { + return bankName != null && !bankName.trim().isEmpty() + && accountNumber != null && !accountNumber.trim().isEmpty(); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java deleted file mode 100644 index f56b89517..000000000 --- a/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java +++ /dev/null @@ -1,13 +0,0 @@ -package server.haengdong.application.request; - -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionStatus; -import server.haengdong.domain.action.Sequence; -import server.haengdong.domain.event.Event; - -public record MemberActionSaveAppRequest(String name, String status) { - - public MemberAction toMemberAction(Event event, Sequence sequence) { - return new MemberAction(event, sequence, name, MemberActionStatus.of(status)); - } -} diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java deleted file mode 100644 index 650b908df..000000000 --- a/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java +++ /dev/null @@ -1,6 +0,0 @@ -package server.haengdong.application.request; - -import java.util.List; - -public record MemberActionsSaveAppRequest(List<MemberActionSaveAppRequest> actions) { -} diff --git a/server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java index d629d3a02..b36d71cc1 100644 --- a/server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java +++ b/server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java @@ -1,7 +1,7 @@ package server.haengdong.application.request; public record MemberNameUpdateAppRequest( - String before, - String after + Long id, + String name ) { } diff --git a/server/src/main/java/server/haengdong/application/request/MemberSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberSaveAppRequest.java new file mode 100644 index 000000000..45dc234e3 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberSaveAppRequest.java @@ -0,0 +1,4 @@ +package server.haengdong.application.request; + +public record MemberSaveAppRequest(String name) { +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberUpdateAppRequest.java new file mode 100644 index 000000000..77df0625b --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberUpdateAppRequest.java @@ -0,0 +1,16 @@ +package server.haengdong.application.request; + + +import server.haengdong.domain.member.Member; +import server.haengdong.domain.event.Event; + +public record MemberUpdateAppRequest( + Long id, + String name, + boolean isDeposited +) { + + public Member toMember(Event event) { + return new Member(id, event, name, isDeposited); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/MembersSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MembersSaveAppRequest.java new file mode 100644 index 000000000..ae0c9fc62 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MembersSaveAppRequest.java @@ -0,0 +1,8 @@ +package server.haengdong.application.request; + +import java.util.List; + +public record MembersSaveAppRequest( + List<MemberSaveAppRequest> members +) { +} diff --git a/server/src/main/java/server/haengdong/application/request/MembersUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/MembersUpdateAppRequest.java new file mode 100644 index 000000000..a8ce8b893 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MembersUpdateAppRequest.java @@ -0,0 +1,6 @@ +package server.haengdong.application.request; + +import java.util.List; + +public record MembersUpdateAppRequest(List<MemberUpdateAppRequest> members) { +} diff --git a/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java b/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java deleted file mode 100644 index 931a5c6ba..000000000 --- a/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java +++ /dev/null @@ -1,61 +0,0 @@ -package server.haengdong.application.response; - -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionStatus; - -public record ActionAppResponse( - Long actionId, - String name, - Long price, - Long sequence, - boolean isFixed, - ActionType actionType -) { - - public ActionAppResponse(Long actionId, String name, Long price, Long sequence, ActionType actionType) { - this(actionId, name, price, sequence, false, actionType); - } - - public static ActionAppResponse of(BillAction billAction) { - return new ActionAppResponse( - billAction.getId(), - billAction.getTitle(), - billAction.getPrice(), - billAction.getSequence().getValue(), - billAction.isFixed(), - ActionAppResponse.ActionType.BILL - ); - } - - public static ActionAppResponse of(MemberAction memberAction) { - MemberActionStatus status = memberAction.getStatus(); - - return new ActionAppResponse( - memberAction.getId(), - memberAction.getMemberName(), - null, - memberAction.getSequence().getValue(), - false, - ActionAppResponse.ActionType.of(status) - ); - } - - public String actionTypeName() { - return actionType.name(); - } - - public enum ActionType { - BILL, - IN, - OUT, - ; - - private static ActionType of(MemberActionStatus memberActionStatus) { - if (MemberActionStatus.IN == memberActionStatus) { - return IN; - } - return OUT; - } - } -} diff --git a/server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java b/server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java deleted file mode 100644 index 3efc7ac9d..000000000 --- a/server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java +++ /dev/null @@ -1,18 +0,0 @@ -package server.haengdong.application.response; - -import server.haengdong.domain.action.BillActionDetail; - -public record BillActionDetailAppResponse( - String name, - Long price, - boolean isFixed -) { - - public static BillActionDetailAppResponse of(BillActionDetail billActionDetail) { - return new BillActionDetailAppResponse( - billActionDetail.getMemberName(), - billActionDetail.getPrice(), - billActionDetail.isFixed() - ); - } -} diff --git a/server/src/main/java/server/haengdong/application/response/BillActionDetailsAppResponse.java b/server/src/main/java/server/haengdong/application/response/BillActionDetailsAppResponse.java deleted file mode 100644 index 061f07816..000000000 --- a/server/src/main/java/server/haengdong/application/response/BillActionDetailsAppResponse.java +++ /dev/null @@ -1,14 +0,0 @@ -package server.haengdong.application.response; - -import java.util.List; -import java.util.stream.Collectors; -import server.haengdong.domain.action.BillActionDetail; - -public record BillActionDetailsAppResponse(List<BillActionDetailAppResponse> billActionDetailAppResponses) { - - public static BillActionDetailsAppResponse of(List<BillActionDetail> billActionDetails) { - return billActionDetails.stream() - .map(BillActionDetailAppResponse::of) - .collect(Collectors.collectingAndThen(Collectors.toList(), BillActionDetailsAppResponse::new)); - } -} diff --git a/server/src/main/java/server/haengdong/application/response/BillAppResponse.java b/server/src/main/java/server/haengdong/application/response/BillAppResponse.java new file mode 100644 index 000000000..8a5a5b2bc --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/BillAppResponse.java @@ -0,0 +1,14 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.bill.Bill; + +public record BillAppResponse( + Long id, + String title, + Long price, + boolean isFixed +) { + public static BillAppResponse of(Bill bill) { + return new BillAppResponse(bill.getId(), bill.getTitle(), bill.getPrice(), bill.isFixed()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/BillDetailAppResponse.java b/server/src/main/java/server/haengdong/application/response/BillDetailAppResponse.java new file mode 100644 index 000000000..6618135cb --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/BillDetailAppResponse.java @@ -0,0 +1,20 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.bill.BillDetail; + +public record BillDetailAppResponse( + Long id, + String memberName, + Long price, + boolean isFixed +) { + + public static BillDetailAppResponse of(BillDetail billDetail) { + return new BillDetailAppResponse( + billDetail.getId(), + billDetail.getMember().getName(), + billDetail.getPrice(), + billDetail.isFixed() + ); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/BillDetailsAppResponse.java b/server/src/main/java/server/haengdong/application/response/BillDetailsAppResponse.java new file mode 100644 index 000000000..3618e0d08 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/BillDetailsAppResponse.java @@ -0,0 +1,14 @@ +package server.haengdong.application.response; + +import java.util.List; +import java.util.stream.Collectors; +import server.haengdong.domain.bill.BillDetail; + +public record BillDetailsAppResponse(List<BillDetailAppResponse> billDetails) { + + public static BillDetailsAppResponse of(List<BillDetail> billDetails) { + return billDetails.stream() + .map(BillDetailAppResponse::of) + .collect(Collectors.collectingAndThen(Collectors.toList(), BillDetailsAppResponse::new)); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java b/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java deleted file mode 100644 index 6c682d3e9..000000000 --- a/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package server.haengdong.application.response; - -import server.haengdong.domain.action.MemberAction; - -public record CurrentMemberAppResponse(String name) { - - public static CurrentMemberAppResponse of(MemberAction memberAction) { - return new CurrentMemberAppResponse(memberAction.getMemberName()); - } -} diff --git a/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java b/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java index 6e38826d4..53fd0b48c 100644 --- a/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java +++ b/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java @@ -2,9 +2,12 @@ import server.haengdong.domain.event.Event; -public record EventDetailAppResponse(String eventName) { +public record EventDetailAppResponse( + String eventName, + String account +) { public static EventDetailAppResponse of(Event event) { - return new EventDetailAppResponse(event.getName()); + return new EventDetailAppResponse(event.getName(), event.getAccount()); } } diff --git a/server/src/main/java/server/haengdong/application/response/LastBillMemberAppResponse.java b/server/src/main/java/server/haengdong/application/response/LastBillMemberAppResponse.java new file mode 100644 index 000000000..abefe009a --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/LastBillMemberAppResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.member.Member; + +public record LastBillMemberAppResponse(Long id, String name) { + + public static LastBillMemberAppResponse of(Member member) { + return new LastBillMemberAppResponse(member.getId(), member.getName()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/MemberAppResponse.java b/server/src/main/java/server/haengdong/application/response/MemberAppResponse.java new file mode 100644 index 000000000..b253ea697 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/MemberAppResponse.java @@ -0,0 +1,12 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.member.Member; + +public record MemberAppResponse( + Long id, + String name +) { + public static MemberAppResponse of(Member member) { + return new MemberAppResponse(member.getId(), member.getName()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java b/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java index 21b6cef56..875578fbc 100644 --- a/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java +++ b/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java @@ -1,4 +1,9 @@ package server.haengdong.application.response; -public record MemberBillReportAppResponse(String name, Long price) { +public record MemberBillReportAppResponse( + Long memberId, + String name, + boolean isDeposited, + Long price +) { } diff --git a/server/src/main/java/server/haengdong/application/response/MemberDepositAppResponse.java b/server/src/main/java/server/haengdong/application/response/MemberDepositAppResponse.java new file mode 100644 index 000000000..94dd77117 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/MemberDepositAppResponse.java @@ -0,0 +1,13 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.member.Member; + +public record MemberDepositAppResponse( + Long id, + String name, + boolean isDeposited +) { + public static MemberDepositAppResponse of(Member member) { + return new MemberDepositAppResponse(member.getId(), member.getName(), member.isDeposited()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/MemberSaveAppResponse.java b/server/src/main/java/server/haengdong/application/response/MemberSaveAppResponse.java new file mode 100644 index 000000000..1d08536ba --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/MemberSaveAppResponse.java @@ -0,0 +1,12 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.member.Member; + +public record MemberSaveAppResponse( + Long id, + String name +) { + public static MemberSaveAppResponse of(Member member) { + return new MemberSaveAppResponse(member.getId(), member.getName()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/MembersAppResponse.java b/server/src/main/java/server/haengdong/application/response/MembersAppResponse.java deleted file mode 100644 index be8378b37..000000000 --- a/server/src/main/java/server/haengdong/application/response/MembersAppResponse.java +++ /dev/null @@ -1,8 +0,0 @@ -package server.haengdong.application.response; - -import java.util.List; - -public record MembersAppResponse( - List<String> memberNames -) { -} diff --git a/server/src/main/java/server/haengdong/application/response/MembersDepositAppResponse.java b/server/src/main/java/server/haengdong/application/response/MembersDepositAppResponse.java new file mode 100644 index 000000000..007904d25 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/MembersDepositAppResponse.java @@ -0,0 +1,15 @@ +package server.haengdong.application.response; + +import java.util.List; +import server.haengdong.domain.member.Member; + +public record MembersDepositAppResponse( + List<MemberDepositAppResponse> members +) { + + public static MembersDepositAppResponse of(List<Member> members) { + return new MembersDepositAppResponse(members.stream() + .map(MemberDepositAppResponse::of) + .toList()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/MembersSaveAppResponse.java b/server/src/main/java/server/haengdong/application/response/MembersSaveAppResponse.java new file mode 100644 index 000000000..e171f9950 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/MembersSaveAppResponse.java @@ -0,0 +1,16 @@ +package server.haengdong.application.response; + +import java.util.List; +import server.haengdong.domain.member.Member; + +public record MembersSaveAppResponse( + List<MemberSaveAppResponse> members +) { + public static MembersSaveAppResponse of(List<Member> members) { + return new MembersSaveAppResponse( + members.stream() + .map(MemberSaveAppResponse::of) + .toList() + ); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/StepAppResponse.java b/server/src/main/java/server/haengdong/application/response/StepAppResponse.java new file mode 100644 index 000000000..2537d1db1 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/StepAppResponse.java @@ -0,0 +1,21 @@ +package server.haengdong.application.response; + +import java.util.List; +import server.haengdong.domain.step.Step; + +public record StepAppResponse( + List<BillAppResponse> bills, + List<MemberAppResponse> members +) { + public static StepAppResponse of(Step step) { + List<BillAppResponse> billAppResponses = step.getBills().stream() + .map(BillAppResponse::of) + .toList(); + + List<MemberAppResponse> memberAppResponses = step.getMembers().stream() + .map(MemberAppResponse::of) + .toList(); + + return new StepAppResponse(billAppResponses, memberAppResponses); + } +} diff --git a/server/src/main/java/server/haengdong/config/AdminInterceptor.java b/server/src/main/java/server/haengdong/config/AdminInterceptor.java index 97bf2c774..6e13f4c96 100644 --- a/server/src/main/java/server/haengdong/config/AdminInterceptor.java +++ b/server/src/main/java/server/haengdong/config/AdminInterceptor.java @@ -27,9 +27,7 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons if (HttpMethod.OPTIONS.equals(method)) { return true; } - validateToken(request); - return true; } diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java deleted file mode 100644 index 47d5d83e5..000000000 --- a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java +++ /dev/null @@ -1,20 +0,0 @@ -package server.haengdong.domain.action; - -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.stereotype.Repository; -import server.haengdong.domain.event.Event; - -@Repository -public interface BillActionDetailRepository extends JpaRepository<BillActionDetail, Long> { - - @Query(""" - select bd - from BillActionDetail bd - where bd.billAction = :billAction - """) - List<BillActionDetail> findAllByBillAction(BillAction billAction); - - List<BillActionDetail> findAllByBillAction_EventAndMemberName(Event event, String memberName); -} diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java deleted file mode 100644 index d05451882..000000000 --- a/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java +++ /dev/null @@ -1,31 +0,0 @@ -package server.haengdong.domain.action; - -import java.util.List; -import java.util.Optional; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; -import server.haengdong.domain.event.Event; - -@Repository -public interface BillActionRepository extends JpaRepository<BillAction, Long> { - - List<BillAction> findByEvent(Event event); - - @Query(""" - select ba - from BillAction ba - where ba.event = :event and ba.sequence.value > :sequence - """) - List<BillAction> findByEventAndGreaterThanSequence(Event event, Long sequence); - - @Query(""" - select ba - from BillAction ba - WHERE ba.event = :event - ORDER BY ba.sequence DESC - LIMIT 1 - """) - Optional<BillAction> findLastByEvent(@Param("event") Event event); -} diff --git a/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java b/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java deleted file mode 100644 index ba380aae5..000000000 --- a/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java +++ /dev/null @@ -1,81 +0,0 @@ -package server.haengdong.domain.action; - -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -public class CurrentMembers { - - private final Set<String> members; - - public CurrentMembers() { - this(new HashSet<>()); - } - - protected CurrentMembers(Set<String> members) { - this.members = members; - } - - public static CurrentMembers of(List<MemberAction> memberActions) { - List<MemberAction> sortedMemberActions = getSortedMemberActions(memberActions); - Set<String> members = new HashSet<>(); - for (MemberAction memberAction : sortedMemberActions) { - String member = memberAction.getMemberName(); - if (memberAction.isSameStatus(MemberActionStatus.IN)) { - members.add(member); - continue; - } - members.remove(member); - } - - return new CurrentMembers(members); - } - - private static List<MemberAction> getSortedMemberActions(List<MemberAction> memberActions) { - return memberActions.stream() - .sorted(Comparator.comparing(MemberAction::getSequence)) - .toList(); - } - - public CurrentMembers addMemberAction(MemberAction memberAction) { - String memberName = memberAction.getMemberName(); - - Set<String> currentMembers = new HashSet<>(members); - - if (memberAction.isIn()) { - currentMembers.add(memberName); - } else { - currentMembers.remove(memberName); - } - return new CurrentMembers(currentMembers); - } - - public void validate(String memberName, MemberActionStatus memberActionStatus) { - if (memberActionStatus == MemberActionStatus.IN && members.contains(memberName)) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_ALREADY_EXIST); - } - if (memberActionStatus == MemberActionStatus.OUT && !members.contains(memberName)) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NOT_EXIST); - } - } - - public boolean isEmpty() { - return members.isEmpty(); - } - - public boolean isNotEmpty() { - return !members.isEmpty(); - } - - public int size() { - return members.size(); - } - - public Set<String> getMembers() { - return Collections.unmodifiableSet(members); - } -} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberAction.java b/server/src/main/java/server/haengdong/domain/action/MemberAction.java deleted file mode 100644 index 18efc1611..000000000 --- a/server/src/main/java/server/haengdong/domain/action/MemberAction.java +++ /dev/null @@ -1,84 +0,0 @@ -package server.haengdong.domain.action; - -import jakarta.persistence.AttributeOverride; -import jakarta.persistence.Column; -import jakarta.persistence.Embedded; -import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.Table; -import jakarta.persistence.UniqueConstraint; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import server.haengdong.domain.event.Event; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"event_id", "sequence"})}) -@Entity -public class MemberAction implements Comparable<MemberAction> { - - public static final int MIN_NAME_LENGTH = 1; - public static final int MAX_NAME_LENGTH = 8; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @JoinColumn(name = "event_id", nullable = false) - @ManyToOne(fetch = FetchType.LAZY) - private Event event; - - @AttributeOverride(name = "value", column = @Column(name = "sequence", nullable = false)) - @Embedded - private Sequence sequence; - - @Column(nullable = false, length = MAX_NAME_LENGTH) - private String memberName; - - @Column(nullable = false) - @Enumerated(EnumType.STRING) - private MemberActionStatus status; - - public MemberAction(Event event, Sequence sequence, String memberName, MemberActionStatus status) { - validateMemberName(memberName); - this.event = event; - this.sequence = sequence; - this.memberName = memberName; - this.status = status; - } - - private void validateMemberName(String memberName) { - int memberLength = memberName.length(); - if (memberLength < MIN_NAME_LENGTH || memberLength > MAX_NAME_LENGTH) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_LENGTH_INVALID); - } - } - - public void updateMemberName(String memberName) { - validateMemberName(memberName); - this.memberName = memberName; - } - - public boolean isIn() { - return status == MemberActionStatus.IN; - } - - public boolean isSameStatus(MemberActionStatus memberActionStatus) { - return status == memberActionStatus; - } - - @Override - public int compareTo(MemberAction o) { - return sequence.compareTo(o.sequence); - } -} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java deleted file mode 100644 index 9aceed477..000000000 --- a/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java +++ /dev/null @@ -1,61 +0,0 @@ -package server.haengdong.domain.action; - -import java.util.List; -import java.util.Optional; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Modifying; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; -import server.haengdong.domain.event.Event; - -@Repository -public interface MemberActionRepository extends JpaRepository<MemberAction, Long> { - - List<MemberAction> findAllByEvent(@Param("event") Event event); - - @Query(""" - select distinct ma.memberName - from MemberAction ma - where ma.event = :event - """) - List<String> findAllUniqueMemberByEvent(Event event); - - @Modifying - @Query(""" - delete - from MemberAction ma - where ma.memberName = :memberName and ma.event = :event - """) - void deleteAllByEventAndMemberName(Event event, String memberName); - - @Modifying - @Query(""" - delete - from MemberAction ma - where ma.memberName = :memberName and ma.sequence.value >= :sequence - """) - void deleteAllByMemberNameAndMinSequence(String memberName, Long sequence); - - List<MemberAction> findAllByEventAndMemberName(Event event, String memberName); - - boolean existsByEventAndMemberName(Event event, String updatedMemberName); - - @Query(""" - select ma - from MemberAction ma - where ma.event = :event and ma.sequence.value < :sequence - """) - List<MemberAction> findByEventAndSequence(Event event, Long sequence); - - @Query(""" - select ma - from MemberAction ma - WHERE ma.event = :event - ORDER BY ma.sequence.value DESC - LIMIT 1 - """) - Optional<MemberAction> findLastByEvent(@Param("event") Event event); - - MemberAction findByIdAndEvent(Long actionId, Event event); -} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java b/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java deleted file mode 100644 index 76c5a66d4..000000000 --- a/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java +++ /dev/null @@ -1,19 +0,0 @@ -package server.haengdong.domain.action; - -import java.util.Arrays; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -public enum MemberActionStatus { - IN, - OUT, - ; - - public static MemberActionStatus of(String status) { - return Arrays.stream(MemberActionStatus.values()) - .filter(s -> s.name().equals(status)) - .findFirst() - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_ACTION_STATUS_INVALID, - String.format(HaengdongErrorCode.MEMBER_ACTION_STATUS_INVALID.getMessage(), status))); - } -} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java b/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java deleted file mode 100644 index 5fcb6ebd3..000000000 --- a/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java +++ /dev/null @@ -1,75 +0,0 @@ -package server.haengdong.domain.action; - -import static java.util.stream.Collectors.toMap; - -import java.util.List; -import java.util.Map; -import java.util.PriorityQueue; -import java.util.function.Function; -import lombok.Getter; - -@Getter -public class MemberBillReport { - - private final Map<String, Long> reports; - - private MemberBillReport(Map<String, Long> reports) { - this.reports = reports; - } - - public static MemberBillReport createByActions(List<BillAction> billActions, List<MemberAction> memberActions) { - PriorityQueue<BillAction> sortedBillActions = new PriorityQueue<>(billActions); - PriorityQueue<MemberAction> sortedMemberActions = new PriorityQueue<>(memberActions); - - Map<String, Long> memberBillReports = initReports(memberActions); - CurrentMembers currentMembers = new CurrentMembers(); - while (!sortedBillActions.isEmpty() && !sortedMemberActions.isEmpty()) { - if (isMemberActionTurn(sortedMemberActions, sortedBillActions)) { - MemberAction memberAction = sortedMemberActions.poll(); - currentMembers = currentMembers.addMemberAction(memberAction); - continue; - } - addBillAction(sortedBillActions, currentMembers, memberBillReports); - } - - while (!sortedBillActions.isEmpty()) { - addBillAction(sortedBillActions, currentMembers, memberBillReports); - } - - return new MemberBillReport(memberBillReports); - } - - private static Map<String, Long> initReports(List<MemberAction> memberActions) { - return memberActions.stream() - .map(MemberAction::getMemberName) - .distinct() - .collect(toMap(Function.identity(), i -> 0L)); - } - - private static boolean isMemberActionTurn( - PriorityQueue<MemberAction> memberActions, - PriorityQueue<BillAction> billActions - ) { - MemberAction memberAction = memberActions.peek(); - BillAction billAction = billActions.peek(); - - return memberAction.getSequence().getValue() < billAction.getSequence().getValue(); - } - - private static void addBillAction( - PriorityQueue<BillAction> sortedBillActions, - CurrentMembers currentMembers, - Map<String, Long> memberBillReports - ) { - BillAction billAction = sortedBillActions.poll(); - if (currentMembers.isEmpty()) { - return; - } - - for (String currentMember : currentMembers.getMembers()) { - Long currentPrice = billAction.findPriceByMemberName(currentMember); - Long price = memberBillReports.get(currentMember) + currentPrice; - memberBillReports.put(currentMember, price); - } - } -} diff --git a/server/src/main/java/server/haengdong/domain/action/Sequence.java b/server/src/main/java/server/haengdong/domain/action/Sequence.java deleted file mode 100644 index 39a99d063..000000000 --- a/server/src/main/java/server/haengdong/domain/action/Sequence.java +++ /dev/null @@ -1,41 +0,0 @@ -package server.haengdong.domain.action; - -import jakarta.persistence.Embeddable; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@EqualsAndHashCode -@Getter -@NoArgsConstructor -@Embeddable -public class Sequence implements Comparable<Sequence> { - - private static final long FIRST_SEQUENCE = 1L; - - private Long value; - - public Sequence(Long value) { - this.value = value; - } - - public static Sequence createFirst() { - return new Sequence(FIRST_SEQUENCE); - } - - public static Sequence getGreater(Sequence first, Sequence second) { - if (first.compareTo(second) > 0) { - return first; - } - return second; - } - - public Sequence next() { - return new Sequence(value + 1); - } - - @Override - public int compareTo(Sequence o) { - return Long.compare(value, o.value); - } -} diff --git a/server/src/main/java/server/haengdong/domain/action/BillAction.java b/server/src/main/java/server/haengdong/domain/bill/Bill.java similarity index 51% rename from server/src/main/java/server/haengdong/domain/action/BillAction.java rename to server/src/main/java/server/haengdong/domain/bill/Bill.java index 56ca8c20e..10043bbcf 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillAction.java +++ b/server/src/main/java/server/haengdong/domain/bill/Bill.java @@ -1,9 +1,7 @@ -package server.haengdong.domain.action; +package server.haengdong.domain.bill; -import jakarta.persistence.AttributeOverride; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; -import jakarta.persistence.Embedded; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; @@ -12,25 +10,24 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; -import jakarta.persistence.Table; -import jakarta.persistence.UniqueConstraint; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; +import server.haengdong.domain.member.Member; import server.haengdong.domain.event.Event; import server.haengdong.exception.HaengdongErrorCode; import server.haengdong.exception.HaengdongException; @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"event_id", "sequence"})}) @Entity -public class BillAction implements Comparable<BillAction> { +public class Bill { public static final int MIN_TITLE_LENGTH = 1; public static final int MAX_TITLE_LENGTH = 30; @@ -46,24 +43,19 @@ public class BillAction implements Comparable<BillAction> { @ManyToOne(fetch = FetchType.LAZY) private Event event; - @AttributeOverride(name = "value", column = @Column(name = "sequence", nullable = false)) - @Embedded - private Sequence sequence; - @Column(nullable = false, length = MAX_TITLE_LENGTH) private String title; @Column(nullable = false) private Long price; - @OneToMany(mappedBy = "billAction", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) - private List<BillActionDetail> billActionDetails = new ArrayList<>(); + @OneToMany(mappedBy = "bill", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) + private List<BillDetail> billDetails = new ArrayList<>(); - public BillAction(Event event, Sequence sequence, String title, Long price) { + public Bill(Event event, String title, Long price) { validateTitle(title); validatePrice(price); this.event = event; - this.sequence = sequence; this.title = title.trim(); this.price = price; } @@ -71,40 +63,38 @@ public BillAction(Event event, Sequence sequence, String title, Long price) { private void validateTitle(String title) { int titleLength = title.trim().length(); if (titleLength < MIN_TITLE_LENGTH || titleLength > MAX_TITLE_LENGTH) { - throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_TITLE_INVALID); + throw new HaengdongException(HaengdongErrorCode.BILL_TITLE_INVALID); } } private void validatePrice(Long price) { if (price < MIN_PRICE || price > MAX_PRICE) { - throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_PRICE_INVALID); + throw new HaengdongException(HaengdongErrorCode.BILL_PRICE_INVALID); } } - public static BillAction create( - Event event, Sequence sequence, String title, Long price, CurrentMembers currentMembers - ) { - BillAction billAction = new BillAction(event, sequence, title, price); - billAction.resetBillActionDetails(currentMembers); - return billAction; + public static Bill create(Event event, String title, Long price, List<Member> members) { + Bill bill = new Bill(event, title, price); + bill.resetBillDetails(members); + return bill; } - public void resetBillActionDetails(CurrentMembers currentMembers) { - this.billActionDetails.clear(); - Iterator<Long> priceIterator = distributePrice(currentMembers.size()).iterator(); + public void resetBillDetails(List<Member> members) { + this.billDetails.clear(); + Iterator<Long> priceIterator = distributePrice(members.size()).iterator(); - for (String member : currentMembers.getMembers()) { - BillActionDetail billActionDetail = new BillActionDetail(this, member, priceIterator.next(), false); - this.billActionDetails.add(billActionDetail); + for (Member member : members) { + BillDetail billDetail = new BillDetail(this, member, priceIterator.next(), false); + this.billDetails.add(billDetail); } } - private void resetBillActionDetails() { - Iterator<Long> priceIterator = distributePrice(billActionDetails.size()).iterator(); + private void resetBillDetails() { + Iterator<Long> priceIterator = distributePrice(billDetails.size()).iterator(); - billActionDetails.forEach(billActionDetail -> { - billActionDetail.updatePrice(priceIterator.next()); - billActionDetail.updateIsFixed(false); + billDetails.forEach(billDetail -> { + billDetail.updatePrice(priceIterator.next()); + billDetail.updateIsFixed(false); }); } @@ -122,42 +112,48 @@ private List<Long> distributePrice(int memberCount) { return results; } + public void removeMemberBillDetail(Member member) { + BillDetail foundBillDetail = billDetails.stream() + .filter(billDetail -> billDetail.isMember(member)) + .findFirst() + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_NOT_FOUND)); + + billDetails.remove(foundBillDetail); + resetBillDetails(); + } + public void update(String title, Long price) { validateTitle(title); validatePrice(price); this.title = title.trim(); this.price = price; - resetBillActionDetails(); + resetBillDetails(); } - public void addDetails(List<BillActionDetail> billActionDetails) { - billActionDetails.forEach(this::addDetail); + public boolean containMember(Member member) { + return billDetails.stream() + .anyMatch(billDetail -> billDetail.isMember(member)); } - private void addDetail(BillActionDetail billActionDetail) { - this.billActionDetails.add(billActionDetail); - billActionDetail.setBillAction(this); - } + public boolean isSameMembers(Bill other) { + Set<Member> members = Set.copyOf(this.getMembers()); + Set<Member> otherMembers = Set.copyOf(other.getMembers()); - public boolean isFixed() { - return billActionDetails.stream() - .anyMatch(BillActionDetail::isFixed); + return members.equals(otherMembers); } public boolean isSamePrice(Long price) { return this.price.equals(price); } - public Long findPriceByMemberName(String memberName) { - return billActionDetails.stream() - .filter(billActionDetail -> billActionDetail.hasMemberName(memberName)) - .map(BillActionDetail::getPrice) - .findFirst() - .orElseGet(() -> DEFAULT_PRICE); + public boolean isFixed() { + return billDetails.stream() + .anyMatch(BillDetail::isFixed); } - @Override - public int compareTo(BillAction o) { - return sequence.compareTo(o.sequence); + public List<Member> getMembers() { + return billDetails.stream() + .map(BillDetail::getMember) + .toList(); } } diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java b/server/src/main/java/server/haengdong/domain/bill/BillDetail.java similarity index 56% rename from server/src/main/java/server/haengdong/domain/action/BillActionDetail.java rename to server/src/main/java/server/haengdong/domain/bill/BillDetail.java index 09776e0d3..6f3bcf973 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java +++ b/server/src/main/java/server/haengdong/domain/bill/BillDetail.java @@ -1,4 +1,4 @@ -package server.haengdong.domain.action; +package server.haengdong.domain.bill; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -11,11 +11,12 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; +import server.haengdong.domain.member.Member; @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Entity -public class BillActionDetail { +public class BillDetail { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -23,10 +24,11 @@ public class BillActionDetail { @JoinColumn(nullable = false) @ManyToOne(fetch = FetchType.LAZY) - private BillAction billAction; + private Bill bill; - @Column(nullable = false) - private String memberName; + @JoinColumn(name = "member_id", nullable = false) + @ManyToOne(fetch = FetchType.LAZY) + private Member member; @Column(nullable = false) private Long price; @@ -34,9 +36,9 @@ public class BillActionDetail { @Column(nullable = false) private boolean isFixed; - public BillActionDetail(BillAction billAction, String memberName, Long price, boolean isFixed) { - this.billAction = billAction; - this.memberName = memberName; + public BillDetail(Bill bill, Member member, Long price, boolean isFixed) { + this.bill = bill; + this.member = member; this.price = price; this.isFixed = isFixed; } @@ -49,19 +51,11 @@ public void updateIsFixed(boolean isFixed) { this.isFixed = isFixed; } - public void updateMemberName(String name) { - this.memberName = name; - } - - public boolean hasMemberName(String memberName) { - return this.memberName.equals(memberName); - } - - public boolean isSameName(String memberName) { - return this.memberName.equals(memberName); + public boolean isSameId(Long id) { + return this.id.equals(id); } - public void setBillAction(BillAction billAction) { - this.billAction = billAction; + public boolean isMember(Member member) { + return this.member.equals(member); } } diff --git a/server/src/main/java/server/haengdong/domain/bill/BillDetailRepository.java b/server/src/main/java/server/haengdong/domain/bill/BillDetailRepository.java new file mode 100644 index 000000000..d49c01ab2 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/bill/BillDetailRepository.java @@ -0,0 +1,26 @@ +package server.haengdong.domain.bill; + +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.member.Member; + +@Repository +public interface BillDetailRepository extends JpaRepository<BillDetail, Long> { + + List<BillDetail> findAllByBill(Bill bill); + + @Query(""" + select bd from BillDetail bd + join fetch bd.member + where bd.bill.id = :billId + """) + List<BillDetail> findAllByBillId(Long billId); + + @Modifying + @Query("delete from BillDetail bd where bd.member = :member") + void deleteAllByMember(@Param("member") Member member); +} diff --git a/server/src/main/java/server/haengdong/domain/bill/BillRepository.java b/server/src/main/java/server/haengdong/domain/bill/BillRepository.java new file mode 100644 index 000000000..2c0b16956 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/bill/BillRepository.java @@ -0,0 +1,15 @@ +package server.haengdong.domain.bill; + +import java.util.List; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.event.Event; + +@Repository +public interface BillRepository extends JpaRepository<Bill, Long> { + + List<Bill> findAllByEvent(Event event); + + Optional<Bill> findFirstByEventOrderByIdDesc(Event event); +} diff --git a/server/src/main/java/server/haengdong/domain/event/Bank.java b/server/src/main/java/server/haengdong/domain/event/Bank.java new file mode 100644 index 000000000..cac1fdc7c --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/Bank.java @@ -0,0 +1,56 @@ +package server.haengdong.domain.event; + +import java.util.Arrays; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +public enum Bank { + WOORI_BANK("우리은행"), + JEIL_BANK("제일은행"), + SHINHAN_BANK("신한은행"), + KB_BANK("KB국민은행"), + HANA_BANK("하나은행"), + CITI_BANK("시티은행"), + IM_BANK("IM뱅크"), + BUSAN_BANK("부산은행"), + GYEONGNAM_BANK("경남은행"), + GWANGJU_BANK("광주은행"), + JEONBUK_BANK("전북은행"), + JEJU_BANK("제주은행"), + IBK_BANK("기업은행"), + KDB_BANK("산업은행"), + SUHYUP_BANK("수협은행"), + NH_BANK("농협은행"), + SAEMAUL_BANK("새마을금고"), + POST_BANK("우체국은행"), + SHINHYEOP_BANK("신협은행"), + SBI_SAVINGS_BANK("SBI저축"), + KAKAO_BANK("카카오뱅크"), + TOSS_BANK("토스뱅크"), + K_BANK("케이뱅크"), + ; + + private final String name; + + Bank(String name) { + this.name = name; + } + + public static void isExists(String bankName) { + Arrays.stream(Bank.values()) + .filter(bank -> bank.name.equals(bankName)) + .findFirst() + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BANK_NAME_INVALID)); + } + + public static String getSupportedBanks() { + return Arrays.stream(Bank.values()) + .map(Bank::getName) + .reduce((bank1, bank2) -> bank1 + ", " + bank2) + .orElse("지원하는 은행이 없습니다."); + } + + public String getName() { + return name; + } +} diff --git a/server/src/main/java/server/haengdong/domain/event/Event.java b/server/src/main/java/server/haengdong/domain/event/Event.java index be8874414..fcbeaab9c 100644 --- a/server/src/main/java/server/haengdong/domain/event/Event.java +++ b/server/src/main/java/server/haengdong/domain/event/Event.java @@ -20,6 +20,8 @@ public class Event { public static final int MIN_NAME_LENGTH = 1; public static final int MAX_NAME_LENGTH = 20; + public static final int MIN_ACCOUNT_NUMBER_LENGTH = 8; + public static final int MAX_ACCOUNT_NUMBER_LENGTH = 30; private static final String SPACES = " "; @Id @@ -36,25 +38,25 @@ public class Event { @Column(nullable = false, unique = true) private String token; + @Column(length = MAX_ACCOUNT_NUMBER_LENGTH) + private String account; + + public Event(String name, String password, String token) { validateName(name); this.name = name; this.password = new Password(password); this.token = token; + this.account = ""; } private void validateName(String name) { int nameLength = name.trim().length(); if (nameLength < MIN_NAME_LENGTH || MAX_NAME_LENGTH < nameLength) { - throw new HaengdongException(HaengdongErrorCode.EVENT_NAME_LENGTH_INVALID, - String.format("행사 이름은 %d자 이상 %d자 이하만 입력 가능합니다. 입력한 이름 길이 : %d", - MIN_NAME_LENGTH, - MAX_NAME_LENGTH, - name.length())); + throw new HaengdongException(HaengdongErrorCode.EVENT_NAME_LENGTH_INVALID); } if (isBlankContinuous(name)) { - throw new HaengdongException(HaengdongErrorCode.EVENT_NAME_CONSECUTIVE_SPACES, - String.format("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s", name)); + throw new HaengdongException(HaengdongErrorCode.EVENT_NAME_CONSECUTIVE_SPACES); } } @@ -69,4 +71,26 @@ public boolean isTokenMismatch(String token) { public boolean isPasswordMismatch(String rawPassword) { return !password.matches(rawPassword); } + + public void rename(String name) { + validateName(name); + this.name = name; + } + + public void changeAccount(String bankName, String accountNumber) { + validateBankName(bankName); + validateAccountNumber(accountNumber); + this.account = bankName + " " + accountNumber; + } + + private void validateBankName(String bankName) { + Bank.isExists(bankName); + } + + private void validateAccountNumber(String accountNumber) { + int accountLength = accountNumber.trim().length(); + if (accountLength < MIN_ACCOUNT_NUMBER_LENGTH || MAX_ACCOUNT_NUMBER_LENGTH < accountLength) { + throw new HaengdongException(HaengdongErrorCode.ACCOUNT_LENGTH_INVALID); + } + } } diff --git a/server/src/main/java/server/haengdong/domain/event/EventImage.java b/server/src/main/java/server/haengdong/domain/event/EventImage.java new file mode 100644 index 000000000..cc5aad0dd --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/EventImage.java @@ -0,0 +1,30 @@ +package server.haengdong.domain.event; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class EventImage { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @JoinColumn(name = "event_id", nullable = false) + @ManyToOne(fetch = FetchType.LAZY) + private Event event; + + @Column(nullable = false) + private String url; +} diff --git a/server/src/main/java/server/haengdong/domain/member/Member.java b/server/src/main/java/server/haengdong/domain/member/Member.java new file mode 100644 index 000000000..d569915e1 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/member/Member.java @@ -0,0 +1,79 @@ +package server.haengdong.domain.member; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; +import java.util.Objects; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import server.haengdong.domain.event.Event; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"event_id", "name"})}) +@Entity +public class Member { + + public static final int MIN_NAME_LENGTH = 1; + public static final int MAX_NAME_LENGTH = 8; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @JoinColumn(name = "event_id", nullable = false) + @ManyToOne(fetch = FetchType.LAZY) + private Event event; + + @Column(nullable = false, length = MAX_NAME_LENGTH) + private String name; + + @Column(nullable = false) + private boolean isDeposited; + + public Member(Event event, String name) { + this(null, event, name, false); + } + + public Member(Long id, Event event, String name, boolean isDeposited) { + validateName(name); + this.id = id; + this.event = event; + this.name = name; + this.isDeposited = isDeposited; + } + + private void validateName(String name) { + int nameLength = name.length(); + if (nameLength < MIN_NAME_LENGTH || nameLength > MAX_NAME_LENGTH) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_LENGTH_INVALID); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Member member = (Member) o; + return Objects.equals(id, member.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/server/src/main/java/server/haengdong/domain/member/MemberBillReport.java b/server/src/main/java/server/haengdong/domain/member/MemberBillReport.java new file mode 100644 index 000000000..25a7d165d --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/member/MemberBillReport.java @@ -0,0 +1,31 @@ +package server.haengdong.domain.member; + +import static java.util.stream.Collectors.toMap; + +import java.util.List; +import java.util.Map; +import lombok.Getter; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.bill.BillDetail; + +@Getter +public class MemberBillReport { + + private final Map<Member, Long> reports; + + private MemberBillReport(Map<Member, Long> reports) { + this.reports = reports; + } + + public static MemberBillReport createByBills(List<Bill> bills) { + Map<Member, Long> reports = bills.stream() + .flatMap(bill -> bill.getBillDetails().stream()) + .collect(toMap( + BillDetail::getMember, + BillDetail::getPrice, + Long::sum + )); + + return new MemberBillReport(reports); + } +} diff --git a/server/src/main/java/server/haengdong/domain/member/MemberRepository.java b/server/src/main/java/server/haengdong/domain/member/MemberRepository.java new file mode 100644 index 000000000..15d57f4ba --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/member/MemberRepository.java @@ -0,0 +1,10 @@ +package server.haengdong.domain.member; + +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import server.haengdong.domain.event.Event; + +public interface MemberRepository extends JpaRepository<Member, Long> { + + List<Member> findAllByEvent(Event event); +} diff --git a/server/src/main/java/server/haengdong/domain/step/Step.java b/server/src/main/java/server/haengdong/domain/step/Step.java new file mode 100644 index 000000000..834d3e715 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/step/Step.java @@ -0,0 +1,50 @@ +package server.haengdong.domain.step; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.member.Member; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +public class Step { + + private final List<Bill> bills; + private final Set<Member> members; + + private Step(List<Bill> bills, Set<Member> members) { + this.bills = bills; + this.members = members; + } + + public static Step of(Bill bill) { + List<Bill> bills = new ArrayList<>(); + bills.add(bill); + Set<Member> members = new HashSet<>(bill.getMembers()); + + return new Step(bills, members); + } + + public void add(Bill bill) { + if (isNotSameMember(bill)) { + throw new HaengdongException(HaengdongErrorCode.DIFFERENT_STEP_MEMBERS); + } + + bills.add(bill); + } + + public boolean isNotSameMember(Bill bill) { + Set<Member> otherMembers = Set.copyOf(bill.getMembers()); + return !members.equals(otherMembers); + } + + public List<Bill> getBills() { + return bills; + } + + public Set<Member> getMembers() { + return members; + } +} diff --git a/server/src/main/java/server/haengdong/domain/step/Steps.java b/server/src/main/java/server/haengdong/domain/step/Steps.java new file mode 100644 index 000000000..f1ad8c746 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/step/Steps.java @@ -0,0 +1,33 @@ +package server.haengdong.domain.step; + +import java.util.ArrayList; +import java.util.List; +import server.haengdong.domain.bill.Bill; + +public class Steps { + + private final List<Step> steps; + + private Steps(List<Step> steps) { + this.steps = steps; + } + + public static Steps of(List<Bill> bills) { + List<Step> steps = new ArrayList<>(); + Step currentStep = null; + + for (Bill bill : bills) { + if (currentStep == null || currentStep.isNotSameMember(bill)) { + currentStep = Step.of(bill); + steps.add(currentStep); + continue; + } + currentStep.add(bill); + } + return new Steps(steps); + } + + public List<Step> getSteps() { + return steps; + } +} diff --git a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java index 475d16c11..e320a77d4 100644 --- a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java +++ b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java @@ -1,8 +1,9 @@ package server.haengdong.exception; import lombok.Getter; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.member.Member; +import server.haengdong.domain.event.Bank; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.Password; @@ -15,29 +16,31 @@ public enum HaengdongErrorCode { EVENT_NAME_LENGTH_INVALID(String.format("행사 이름은 %d자 이상 %d자 이하만 입력 가능합니다.", Event.MIN_NAME_LENGTH, Event.MAX_NAME_LENGTH)), - EVENT_NAME_CONSECUTIVE_SPACES("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s"), + EVENT_NAME_CONSECUTIVE_SPACES("행사 이름에는 공백 문자가 연속될 수 없습니다."), EVENT_PASSWORD_FORMAT_INVALID(String.format("비밀번호는 %d자리 숫자만 가능합니다.", Password.PASSWORD_LENGTH)), - - ACTION_NOT_FOUND("존재하지 않는 액션입니다."), + BANK_NAME_INVALID(String.format("지원하지 않는 은행입니다. 지원하는 은행 목록: %s", + Bank.getSupportedBanks())), + ACCOUNT_LENGTH_INVALID(String.format("계좌번호는 %d자 이상 %d자 이하만 입력 가능합니다.", + Event.MIN_ACCOUNT_NUMBER_LENGTH, + Event.MAX_ACCOUNT_NUMBER_LENGTH)), MEMBER_NAME_LENGTH_INVALID(String.format("멤버 이름은 %d자 이상 %d자 이하만 입력 가능합니다.", - MemberAction.MIN_NAME_LENGTH, - MemberAction.MAX_NAME_LENGTH)), + Member.MIN_NAME_LENGTH, + Member.MAX_NAME_LENGTH)), MEMBER_NAME_DUPLICATE("중복된 행사 참여 인원 이름이 존재합니다."), - MEMBER_NOT_EXIST("현재 참여하고 있지 않는 인원이 존재합니다."), + MEMBER_NOT_FOUND("존재하지 않는 참여자입니다."), MEMBER_ALREADY_EXIST("현재 참여하고 있는 인원이 존재합니다."), MEMBER_NAME_CHANGE_DUPLICATE("중복된 참여 인원 이름 변경 요청이 존재합니다."), - MEMBER_ACTION_NOT_FOUND("존재하지 않는 멤버 액션입니다."), - MEMBER_ACTION_STATUS_INVALID("멤버 액션은 IN, OUT만 가능합니다. 입력한 멤버 액션: %s"), + BILL_NOT_FOUND("존재하지 않는 지출입니다."), + BILL_TITLE_INVALID(String.format("앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다.", + Bill.MIN_TITLE_LENGTH, + Bill.MAX_TITLE_LENGTH)), + BILL_PRICE_INVALID(String.format("지출 금액은 %,d 이하의 자연수여야 합니다.", Bill.MAX_PRICE)), + BILL_DETAIL_NOT_FOUND("존재하지 않는 참여자 지출입니다."), + BILL_PRICE_NOT_MATCHED("지출 총액이 일치하지 않습니다."), - BILL_ACTION_NOT_FOUND("존재하지 않는 지출 액션입니다."), - BILL_ACTION_TITLE_INVALID(String.format("앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다.", - BillAction.MIN_TITLE_LENGTH, - BillAction.MAX_TITLE_LENGTH)), - BILL_ACTION_PRICE_INVALID(String.format("지출 금액은 %,d 이하의 자연수여야 합니다.", BillAction.MAX_PRICE)), - BILL_ACTION_DETAIL_NOT_FOUND("존재하지 않는 참여자 지출입니다."), - BILL_ACTION_PRICE_NOT_MATCHED("지출 총액이 일치하지 않습니다."), + DIFFERENT_STEP_MEMBERS("회원 목록이 일치하지 않습니다."), /* Authentication */ diff --git a/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java b/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java deleted file mode 100644 index 924bcf32c..000000000 --- a/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java +++ /dev/null @@ -1,27 +0,0 @@ -package server.haengdong.presentation; - -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RestController; -import server.haengdong.application.BillActionDetailService; -import server.haengdong.application.response.BillActionDetailsAppResponse; -import server.haengdong.presentation.response.BillActionDetailsResponse; - -@RequiredArgsConstructor -@RestController -public class BillActionDetailController { - - private final BillActionDetailService billActionDetailService; - - @GetMapping("/api/events/{eventId}/bill-actions/{actionId}/fixed") - public ResponseEntity<BillActionDetailsResponse> findBillActionDetails( - @PathVariable("eventId") String token, - @PathVariable("actionId") Long actionId - ) { - BillActionDetailsAppResponse appResponse = billActionDetailService.findBillActionDetails(token, actionId); - - return ResponseEntity.ok(BillActionDetailsResponse.of(appResponse)); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/BillController.java b/server/src/main/java/server/haengdong/presentation/BillController.java new file mode 100644 index 000000000..f1a4f74f4 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/BillController.java @@ -0,0 +1,35 @@ +package server.haengdong.presentation; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.BillService; +import server.haengdong.application.response.BillDetailsAppResponse; +import server.haengdong.presentation.response.BillDetailsResponse; +import server.haengdong.presentation.response.StepsResponse; + +@RequiredArgsConstructor +@RestController +public class BillController { + + private final BillService billService; + + @GetMapping("/api/events/{eventId}/bills") + public ResponseEntity<StepsResponse> findBills(@PathVariable("eventId") String token) { + StepsResponse stepsResponse = StepsResponse.of(billService.findSteps(token)); + + return ResponseEntity.ok(stepsResponse); + } + + @GetMapping("/api/events/{eventId}/bills/{billId}/details") + public ResponseEntity<BillDetailsResponse> findBillDetails( + @PathVariable("eventId") String token, + @PathVariable("billId") Long billId + ) { + BillDetailsAppResponse appResponse = billService.findBillDetails(token, billId); + + return ResponseEntity.ok(BillDetailsResponse.of(appResponse)); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java index af725864d..77caa744a 100644 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -15,17 +15,13 @@ import org.springframework.web.bind.annotation.RestController; import server.haengdong.application.AuthService; import server.haengdong.application.EventService; -import server.haengdong.application.response.ActionAppResponse; import server.haengdong.application.response.MemberBillReportAppResponse; import server.haengdong.infrastructure.auth.CookieProperties; import server.haengdong.presentation.request.EventLoginRequest; import server.haengdong.presentation.request.EventSaveRequest; -import server.haengdong.presentation.response.ActionsResponse; import server.haengdong.presentation.response.EventDetailResponse; import server.haengdong.presentation.response.EventResponse; import server.haengdong.presentation.response.MemberBillReportsResponse; -import server.haengdong.presentation.response.MembersResponse; -import server.haengdong.presentation.response.StepsResponse; @Slf4j @RequiredArgsConstructor @@ -44,28 +40,6 @@ public ResponseEntity<EventDetailResponse> findEvent(@PathVariable("eventId") St return ResponseEntity.ok(eventDetailResponse); } - @GetMapping("/api/events/{eventId}/actions") - public ResponseEntity<StepsResponse> findActions(@PathVariable("eventId") String token) { - StepsResponse stepsResponse = StepsResponse.of(eventService.findActions(token)); - - return ResponseEntity.ok(stepsResponse); - } - - @GetMapping("/api/events/{eventId}/actions/v2") - public ResponseEntity<ActionsResponse> findActions2(@PathVariable("eventId") String token) { - List<ActionAppResponse> actions = eventService.findActions(token); - ActionsResponse actionsResponse = ActionsResponse.of(actions); - - return ResponseEntity.ok(actionsResponse); - } - - @GetMapping("/api/events/{eventId}/members") - public ResponseEntity<MembersResponse> findAllMembers(@PathVariable("eventId") String token) { - MembersResponse response = MembersResponse.of(eventService.findAllMembers(token)); - - return ResponseEntity.ok(response); - } - @GetMapping("/api/events/{eventId}/reports") public ResponseEntity<MemberBillReportsResponse> getMemberBillReports(@PathVariable("eventId") String token) { List<MemberBillReportAppResponse> memberBillReports = eventService.getMemberBillReports(token); diff --git a/server/src/main/java/server/haengdong/presentation/MemberActionController.java b/server/src/main/java/server/haengdong/presentation/MemberController.java similarity index 51% rename from server/src/main/java/server/haengdong/presentation/MemberActionController.java rename to server/src/main/java/server/haengdong/presentation/MemberController.java index 3a20339fd..f5662f9b2 100644 --- a/server/src/main/java/server/haengdong/presentation/MemberActionController.java +++ b/server/src/main/java/server/haengdong/presentation/MemberController.java @@ -2,23 +2,33 @@ import java.util.List; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; -import server.haengdong.application.MemberActionService; -import server.haengdong.application.response.CurrentMemberAppResponse; +import server.haengdong.application.MemberService; +import server.haengdong.application.response.MemberAppResponse; import server.haengdong.presentation.response.CurrentMembersResponse; +import server.haengdong.presentation.response.MembersResponse; +@Slf4j @RequiredArgsConstructor @RestController -public class MemberActionController { +public class MemberController { - private final MemberActionService memberActionService; + private final MemberService memberService; + + @GetMapping("/api/events/{eventId}/members") + public ResponseEntity<MembersResponse> findAllMembers(@PathVariable("eventId") String token) { + MembersResponse response = MembersResponse.of(memberService.findAllMembers(token)); + + return ResponseEntity.ok(response); + } @GetMapping("/api/events/{eventId}/members/current") public ResponseEntity<CurrentMembersResponse> getCurrentMembers(@PathVariable("eventId") String token) { - List<CurrentMemberAppResponse> currentMembers = memberActionService.getCurrentMembers(token); + List<MemberAppResponse> currentMembers = memberService.getCurrentMembers(token); return ResponseEntity.ok() .body(CurrentMembersResponse.of(currentMembers)); diff --git a/server/src/main/java/server/haengdong/presentation/admin/AdminBillActionController.java b/server/src/main/java/server/haengdong/presentation/admin/AdminBillActionController.java deleted file mode 100644 index f3e66cdb9..000000000 --- a/server/src/main/java/server/haengdong/presentation/admin/AdminBillActionController.java +++ /dev/null @@ -1,66 +0,0 @@ -package server.haengdong.presentation.admin; - -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; -import server.haengdong.application.BillActionDetailService; -import server.haengdong.application.BillActionService; -import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; -import server.haengdong.presentation.request.BillActionUpdateRequest; -import server.haengdong.presentation.request.BillActionsSaveRequest; - -@RequiredArgsConstructor -@RestController -public class AdminBillActionController { - - private final BillActionService billActionService; - private final BillActionDetailService billActionDetailService; - - @PostMapping("/api/admin/events/{eventId}/bill-actions") - public ResponseEntity<Void> saveAllBillAction( - @PathVariable("eventId") String token, - @Valid @RequestBody BillActionsSaveRequest request - ) { - billActionService.saveAllBillAction(token, request.toAppRequests()); - - return ResponseEntity.ok().build(); - } - - @PutMapping("/api/admin/events/{eventId}/bill-actions/{actionId}") - public ResponseEntity<Void> updateBillAction( - @PathVariable("eventId") String token, - @PathVariable("actionId") Long actionId, - @Valid @RequestBody BillActionUpdateRequest request - ) { - billActionService.updateBillAction(token, actionId, request.toAppResponse()); - - return ResponseEntity.ok().build(); - } - - @PutMapping("/api/admin/events/{eventId}/bill-actions/{actionId}/fixed") - public ResponseEntity<Void> updateBillActionDetails( - @PathVariable("eventId") String token, - @PathVariable("actionId") Long actionId, - @Valid @RequestBody BillActionDetailsUpdateRequest request - ) { - billActionDetailService.updateBillActionDetails(token, actionId, request.toAppRequest()); - - return ResponseEntity.ok().build(); - } - - @DeleteMapping("/api/admin/events/{eventId}/bill-actions/{actionId}") - public ResponseEntity<Void> deleteBillAction( - @PathVariable("eventId") String token, - @PathVariable("actionId") Long actionId - ) { - billActionService.deleteBillAction(token, actionId); - - return ResponseEntity.ok().build(); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/admin/AdminBillController.java b/server/src/main/java/server/haengdong/presentation/admin/AdminBillController.java new file mode 100644 index 000000000..5e65c04f9 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/admin/AdminBillController.java @@ -0,0 +1,64 @@ +package server.haengdong.presentation.admin; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.BillService; +import server.haengdong.presentation.request.BillDetailsUpdateRequest; +import server.haengdong.presentation.request.BillSaveRequest; +import server.haengdong.presentation.request.BillUpdateRequest; + +@RequiredArgsConstructor +@RestController +public class AdminBillController { + + private final BillService billService; + + @PostMapping("/api/admin/events/{eventId}/bills") + public ResponseEntity<Void> saveAllBill( + @PathVariable("eventId") String token, + @Valid @RequestBody BillSaveRequest request + ) { + billService.saveBill(token, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } + + @DeleteMapping("/api/admin/events/{eventId}/bills/{billId}") + public ResponseEntity<Void> deleteBill( + @PathVariable("eventId") String token, + @PathVariable("billId") Long billId + ) { + billService.deleteBill(token, billId); + + return ResponseEntity.ok().build(); + } + + @PutMapping("/api/admin/events/{eventId}/bills/{billId}") + public ResponseEntity<Void> updateBill( + @PathVariable("eventId") String token, + @PathVariable("billId") Long billId, + @Valid @RequestBody BillUpdateRequest request + ) { + billService.updateBill(token, billId, request.toAppResponse()); + + return ResponseEntity.ok().build(); + } + + @PutMapping("/api/admin/events/{eventId}/bills/{billId}/details") + public ResponseEntity<Void> updateBillDetails( + @PathVariable("eventId") String token, + @PathVariable("billId") Long billId, + @Valid @RequestBody BillDetailsUpdateRequest request + ) { + billService.updateBillDetails(token, billId, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/admin/AdminEventController.java b/server/src/main/java/server/haengdong/presentation/admin/AdminEventController.java index aa4a8a278..46d11cdd5 100644 --- a/server/src/main/java/server/haengdong/presentation/admin/AdminEventController.java +++ b/server/src/main/java/server/haengdong/presentation/admin/AdminEventController.java @@ -3,36 +3,33 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import server.haengdong.application.EventService; -import server.haengdong.infrastructure.auth.CookieProperties; -import server.haengdong.presentation.request.MemberNamesUpdateRequest; +import server.haengdong.presentation.request.EventUpdateRequest; @Slf4j @RequiredArgsConstructor -@EnableConfigurationProperties(CookieProperties.class) @RestController public class AdminEventController { private final EventService eventService; @PostMapping("/api/admin/events/{eventId}/auth") - public ResponseEntity<Void> authenticate(@PathVariable("eventId") String token) { + public ResponseEntity<Void> authenticate() { return ResponseEntity.ok().build(); } - @PutMapping("/api/admin/events/{eventId}/members/nameChange") - public ResponseEntity<Void> updateMember( + @PatchMapping("/api/admin/events/{eventId}") + public ResponseEntity<Void> updateEvent( @PathVariable("eventId") String token, - @Valid @RequestBody MemberNamesUpdateRequest request + @Valid @RequestBody EventUpdateRequest request ) { - eventService.updateMember(token, request.toAppRequest()); + eventService.updateEvent(token, request.toAppRequest()); return ResponseEntity.ok().build(); } diff --git a/server/src/main/java/server/haengdong/presentation/admin/AdminMemberActionController.java b/server/src/main/java/server/haengdong/presentation/admin/AdminMemberActionController.java deleted file mode 100644 index c45f18405..000000000 --- a/server/src/main/java/server/haengdong/presentation/admin/AdminMemberActionController.java +++ /dev/null @@ -1,48 +0,0 @@ -package server.haengdong.presentation.admin; - -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; -import server.haengdong.application.MemberActionService; -import server.haengdong.presentation.request.MemberActionsSaveRequest; - -@RequiredArgsConstructor -@RestController -public class AdminMemberActionController { - - private final MemberActionService memberActionService; - - @PostMapping("/api/admin/events/{eventId}/member-actions") - public ResponseEntity<Void> saveMemberAction( - @PathVariable("eventId") String token, - @RequestBody MemberActionsSaveRequest request - ) { - memberActionService.saveMemberAction(token, request.toAppRequest()); - - return ResponseEntity.ok().build(); - } - - @DeleteMapping("/api/admin/events/{eventId}/members/{memberName}") - public ResponseEntity<Void> deleteMember( - @PathVariable("eventId") String token, - @PathVariable("memberName") String memberName - ) { - memberActionService.deleteMember(token, memberName); - - return ResponseEntity.ok().build(); - } - - @DeleteMapping("/api/admin/events/{eventId}/member-actions/{actionId}") - public ResponseEntity<Void> deleteMemberAction( - @PathVariable("eventId") String token, - @PathVariable("actionId") Long actionId - ) { - memberActionService.deleteMemberAction(token, actionId); - - return ResponseEntity.ok().build(); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/admin/AdminMemberController.java b/server/src/main/java/server/haengdong/presentation/admin/AdminMemberController.java new file mode 100644 index 000000000..22cb0190a --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/admin/AdminMemberController.java @@ -0,0 +1,55 @@ +package server.haengdong.presentation.admin; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.MemberService; +import server.haengdong.application.response.MembersSaveAppResponse; +import server.haengdong.presentation.request.MembersSaveRequest; +import server.haengdong.presentation.request.MembersUpdateRequest; +import server.haengdong.presentation.response.MembersSaveResponse; + +@Slf4j +@RequiredArgsConstructor +@RestController +public class AdminMemberController { + + private final MemberService memberService; + + @PostMapping("/api/admin/events/{eventId}/members") + public ResponseEntity<MembersSaveResponse> saveMembers( + @PathVariable("eventId") String token, + @Valid @RequestBody MembersSaveRequest request + ) { + MembersSaveAppResponse response = memberService.saveMembers(token, request.toAppRequest()); + + return ResponseEntity.ok(MembersSaveResponse.of(response)); + } + + @PutMapping("/api/admin/events/{eventId}/members") + public ResponseEntity<Void> updateMembers( + @PathVariable("eventId") String token, + @Valid @RequestBody MembersUpdateRequest request + ) { + memberService.updateMembers(token, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } + + @DeleteMapping("/api/admin/events/{eventId}/members/{memberId}") + public ResponseEntity<Void> deleteMember( + @PathVariable("eventId") String token, + @PathVariable("memberId") Long memberId + ) { + memberService.deleteMember(token, memberId); + + return ResponseEntity.ok().build(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java deleted file mode 100644 index 21c4bd60f..000000000 --- a/server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java +++ /dev/null @@ -1,21 +0,0 @@ -package server.haengdong.presentation.request; - -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import server.haengdong.application.request.BillActionDetailUpdateAppRequest; - -public record BillActionDetailUpdateRequest( - - @NotBlank(message = "맴버 이름은 공백일 수 없습니다.") - String name, - - @NotNull(message = "지출 금액은 공백일 수 없습니다.") - Long price, - - @NotNull(message = "지출 금액은 공백일 수 없습니다.") - boolean isFixed -) { - public BillActionDetailUpdateAppRequest toAppRequest() { - return new BillActionDetailUpdateAppRequest(this.name, this.price, this.isFixed); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java deleted file mode 100644 index fafbb8fd7..000000000 --- a/server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java +++ /dev/null @@ -1,16 +0,0 @@ -package server.haengdong.presentation.request; - -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotEmpty; -import java.util.List; -import server.haengdong.application.request.BillActionDetailsUpdateAppRequest; - -public record BillActionDetailsUpdateRequest( - @Valid @NotEmpty List<BillActionDetailUpdateRequest> members -) { - public BillActionDetailsUpdateAppRequest toAppRequest() { - return new BillActionDetailsUpdateAppRequest(members.stream() - .map(BillActionDetailUpdateRequest::toAppRequest) - .toList()); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java deleted file mode 100644 index 6727d4cf1..000000000 --- a/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java +++ /dev/null @@ -1,18 +0,0 @@ -package server.haengdong.presentation.request; - -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotEmpty; -import java.util.List; -import server.haengdong.application.request.BillActionAppRequest; - -public record BillActionsSaveRequest( - - @Valid @NotEmpty List<BillActionSaveRequest> actions -) { - - public List<BillActionAppRequest> toAppRequests() { - return actions.stream() - .map(BillActionSaveRequest::toAppRequest) - .toList(); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillDetailUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillDetailUpdateRequest.java new file mode 100644 index 000000000..accaf8e00 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillDetailUpdateRequest.java @@ -0,0 +1,20 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotNull; +import server.haengdong.application.request.BillDetailUpdateAppRequest; + +public record BillDetailUpdateRequest( + + @NotNull(message = "지출 상세 ID는 공백일 수 없습니다.") + Long id, + + @NotNull(message = "지출 금액은 공백일 수 없습니다.") + Long price, + + @NotNull(message = "지출 금액은 공백일 수 없습니다.") + boolean isFixed +) { + public BillDetailUpdateAppRequest toAppRequest() { + return new BillDetailUpdateAppRequest(this.id, this.price, this.isFixed); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillDetailsUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillDetailsUpdateRequest.java new file mode 100644 index 000000000..f09d101bd --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillDetailsUpdateRequest.java @@ -0,0 +1,16 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import java.util.List; +import server.haengdong.application.request.BillDetailsUpdateAppRequest; + +public record BillDetailsUpdateRequest( + @Valid @NotEmpty List<BillDetailUpdateRequest> billDetails +) { + public BillDetailsUpdateAppRequest toAppRequest() { + return new BillDetailsUpdateAppRequest(billDetails.stream() + .map(BillDetailUpdateRequest::toAppRequest) + .toList()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillSaveRequest.java similarity index 50% rename from server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java rename to server/src/main/java/server/haengdong/presentation/request/BillSaveRequest.java index 680006816..1a7365a6e 100644 --- a/server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/BillSaveRequest.java @@ -1,18 +1,24 @@ package server.haengdong.presentation.request; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; -import server.haengdong.application.request.BillActionUpdateAppRequest; +import java.util.List; +import server.haengdong.application.request.BillAppRequest; -public record BillActionUpdateRequest( +public record BillSaveRequest( @NotBlank(message = "지출 내역 제목은 공백일 수 없습니다.") String title, @NotNull(message = "지출 금액은 공백일 수 없습니다.") - Long price + Long price, + + @NotEmpty + List<Long> memberIds ) { - public BillActionUpdateAppRequest toAppResponse() { - return new BillActionUpdateAppRequest(title, price); + + public BillAppRequest toAppRequest() { + return new BillAppRequest(title, price, memberIds); } } diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillUpdateRequest.java similarity index 63% rename from server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java rename to server/src/main/java/server/haengdong/presentation/request/BillUpdateRequest.java index a47ff8316..a37c75013 100644 --- a/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/BillUpdateRequest.java @@ -2,9 +2,9 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import server.haengdong.application.request.BillActionAppRequest; +import server.haengdong.application.request.BillUpdateAppRequest; -public record BillActionSaveRequest( +public record BillUpdateRequest( @NotBlank(message = "지출 내역 제목은 공백일 수 없습니다.") String title, @@ -12,8 +12,7 @@ public record BillActionSaveRequest( @NotNull(message = "지출 금액은 공백일 수 없습니다.") Long price ) { - - public BillActionAppRequest toAppRequest() { - return new BillActionAppRequest(title, price); + public BillUpdateAppRequest toAppResponse() { + return new BillUpdateAppRequest(title, price); } } diff --git a/server/src/main/java/server/haengdong/presentation/request/EventUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/EventUpdateRequest.java new file mode 100644 index 000000000..cafd12ea6 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/EventUpdateRequest.java @@ -0,0 +1,14 @@ +package server.haengdong.presentation.request; + +import server.haengdong.application.request.EventUpdateAppRequest; + +public record EventUpdateRequest( + String eventName, + String bankName, + String accountNumber +) { + + public EventUpdateAppRequest toAppRequest() { + return new EventUpdateAppRequest(eventName, bankName, accountNumber); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java deleted file mode 100644 index 41e95cc3c..000000000 --- a/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java +++ /dev/null @@ -1,25 +0,0 @@ -package server.haengdong.presentation.request; - -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotEmpty; -import java.util.List; -import server.haengdong.application.request.MemberActionSaveAppRequest; -import server.haengdong.application.request.MemberActionsSaveAppRequest; - -public record MemberActionsSaveRequest( - - @NotEmpty - List<String> members, - - @NotBlank(message = "멤버 액션은 공백일 수 없습니다.") - String status -) { - - public MemberActionsSaveAppRequest toAppRequest() { - List<MemberActionSaveAppRequest> appRequests = members.stream() - .map(name -> new MemberActionSaveAppRequest(name, status)) - .toList(); - - return new MemberActionsSaveAppRequest(appRequests); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberNameUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberNameUpdateRequest.java index 3cd2294ca..fb1ff655f 100644 --- a/server/src/main/java/server/haengdong/presentation/request/MemberNameUpdateRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/MemberNameUpdateRequest.java @@ -1,18 +1,19 @@ package server.haengdong.presentation.request; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import server.haengdong.application.request.MemberNameUpdateAppRequest; public record MemberNameUpdateRequest( - @NotBlank(message = "멤버 이름은 공백일 수 없습니다.") - String before, + @NotNull(message = "멤버 id는 공백일 수 없습니다.") + Long id, @NotBlank(message = "멤버 이름은 공백일 수 없습니다.") - String after + String name ) { public MemberNameUpdateAppRequest toAppRequest() { - return new MemberNameUpdateAppRequest(before, after); + return new MemberNameUpdateAppRequest(id, name); } } diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java index 872aa55de..79c46590d 100644 --- a/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java @@ -6,12 +6,15 @@ import server.haengdong.application.request.MemberNamesUpdateAppRequest; public record MemberNamesUpdateRequest( - @Valid @NotEmpty List<MemberNameUpdateRequest> members + @Valid + @NotEmpty + List<MemberNameUpdateRequest> members ) { public MemberNamesUpdateAppRequest toAppRequest() { return new MemberNamesUpdateAppRequest(members.stream() - .map(MemberNameUpdateRequest::toAppRequest) - .toList()); + .map(MemberNameUpdateRequest::toAppRequest) + .toList() + ); } } diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberSaveRequest.java new file mode 100644 index 000000000..f1d75e1b1 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MemberSaveRequest.java @@ -0,0 +1,4 @@ +package server.haengdong.presentation.request; + +public record MemberSaveRequest(String name) { +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberUpdateRequest.java new file mode 100644 index 000000000..1f3bfe95a --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MemberUpdateRequest.java @@ -0,0 +1,22 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import server.haengdong.application.request.MemberUpdateAppRequest; + +public record MemberUpdateRequest( + + @NotNull(message = "멤버 ID는 공백일 수 없습니다.") + Long id, + + @NotBlank(message = "멤버 이름은 공백일 수 없습니다.") + String name, + + @NotNull(message = "입금 여부는 공백일 수 없습니다.") + boolean isDeposited +) { + + public MemberUpdateAppRequest toAppRequest() { + return new MemberUpdateAppRequest(id, name, isDeposited); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MembersSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/MembersSaveRequest.java new file mode 100644 index 000000000..c5e2100fd --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MembersSaveRequest.java @@ -0,0 +1,14 @@ +package server.haengdong.presentation.request; + +import java.util.List; +import server.haengdong.application.request.MemberSaveAppRequest; +import server.haengdong.application.request.MembersSaveAppRequest; + +public record MembersSaveRequest(List<MemberSaveRequest> members) { + public MembersSaveAppRequest toAppRequest() { + return new MembersSaveAppRequest(members.stream() + .map(member -> new MemberSaveAppRequest(member.name())) + .toList()); + + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MembersUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/MembersUpdateRequest.java new file mode 100644 index 000000000..db3715130 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MembersUpdateRequest.java @@ -0,0 +1,20 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import java.util.List; +import server.haengdong.application.request.MembersUpdateAppRequest; + +public record MembersUpdateRequest( + + @Valid + @NotNull + List<MemberUpdateRequest> members +) { + + public MembersUpdateAppRequest toAppRequest() { + return new MembersUpdateAppRequest(members.stream() + .map(MemberUpdateRequest::toAppRequest) + .toList()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java b/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java deleted file mode 100644 index ea26ea769..000000000 --- a/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java +++ /dev/null @@ -1,26 +0,0 @@ -package server.haengdong.presentation.response; - -import server.haengdong.application.response.ActionAppResponse; - -public record ActionResponse( - Long actionId, - String name, - Long price, - Long sequence, - boolean isFixed -) { - - public ActionResponse(Long actionId, String name, Long price, Long sequence) { - this(actionId, name, price, sequence, false); - } - - public static ActionResponse of(ActionAppResponse actionAppResponse) { - return new ActionResponse( - actionAppResponse.actionId(), - actionAppResponse.name(), - actionAppResponse.price(), - actionAppResponse.sequence(), - actionAppResponse.isFixed() - ); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java b/server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java deleted file mode 100644 index ea46c5bd9..000000000 --- a/server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java +++ /dev/null @@ -1,22 +0,0 @@ -package server.haengdong.presentation.response; - -import server.haengdong.application.response.ActionAppResponse; - -public record ActionResponse2( - Long actionId, - String name, - Long price, - Long sequence, - String type -) { - - public static ActionResponse2 of(ActionAppResponse actionAppResponse) { - return new ActionResponse2( - actionAppResponse.actionId(), - actionAppResponse.name(), - actionAppResponse.price(), - actionAppResponse.sequence(), - actionAppResponse.actionType().name() - ); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java b/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java deleted file mode 100644 index c8ae780e3..000000000 --- a/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java +++ /dev/null @@ -1,14 +0,0 @@ -package server.haengdong.presentation.response; - -import java.util.List; -import server.haengdong.application.response.ActionAppResponse; - -public record ActionsResponse( - List<ActionResponse2> actions -) { - public static ActionsResponse of(List<ActionAppResponse> actions) { - return new ActionsResponse(actions.stream() - .map(ActionResponse2::of) - .toList()); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java b/server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java deleted file mode 100644 index 10f71b82e..000000000 --- a/server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java +++ /dev/null @@ -1,18 +0,0 @@ -package server.haengdong.presentation.response; - -import server.haengdong.application.response.BillActionDetailAppResponse; - -public record BillActionDetailResponse( - String name, - Long price, - boolean isFixed -) { - - public static BillActionDetailResponse of(BillActionDetailAppResponse billActionDetailAppResponse) { - return new BillActionDetailResponse( - billActionDetailAppResponse.name(), - billActionDetailAppResponse.price(), - billActionDetailAppResponse.isFixed() - ); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/response/BillActionDetailsResponse.java b/server/src/main/java/server/haengdong/presentation/response/BillActionDetailsResponse.java deleted file mode 100644 index 182e76db6..000000000 --- a/server/src/main/java/server/haengdong/presentation/response/BillActionDetailsResponse.java +++ /dev/null @@ -1,16 +0,0 @@ -package server.haengdong.presentation.response; - -import java.util.List; -import java.util.stream.Collectors; -import server.haengdong.application.response.BillActionDetailsAppResponse; - -public record BillActionDetailsResponse( - List<BillActionDetailResponse> members -) { - - public static BillActionDetailsResponse of(BillActionDetailsAppResponse billActionDetailsAppResponse) { - return billActionDetailsAppResponse.billActionDetailAppResponses().stream() - .map(BillActionDetailResponse::of) - .collect(Collectors.collectingAndThen(Collectors.toList(), BillActionDetailsResponse::new)); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/response/BillDetailResponse.java b/server/src/main/java/server/haengdong/presentation/response/BillDetailResponse.java new file mode 100644 index 000000000..9ff993b8a --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/BillDetailResponse.java @@ -0,0 +1,20 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.BillDetailAppResponse; + +public record BillDetailResponse( + Long id, + String memberName, + Long price, + boolean isFixed +) { + + public static BillDetailResponse of(BillDetailAppResponse billDetailAppResponse) { + return new BillDetailResponse( + billDetailAppResponse.id(), + billDetailAppResponse.memberName(), + billDetailAppResponse.price(), + billDetailAppResponse.isFixed() + ); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/BillDetailsResponse.java b/server/src/main/java/server/haengdong/presentation/response/BillDetailsResponse.java new file mode 100644 index 000000000..888b0160d --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/BillDetailsResponse.java @@ -0,0 +1,16 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import java.util.stream.Collectors; +import server.haengdong.application.response.BillDetailsAppResponse; + +public record BillDetailsResponse( + List<BillDetailResponse> members +) { + + public static BillDetailsResponse of(BillDetailsAppResponse billDetailsAppResponse) { + return billDetailsAppResponse.billDetails().stream() + .map(BillDetailResponse::of) + .collect(Collectors.collectingAndThen(Collectors.toList(), BillDetailsResponse::new)); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/BillResponse.java b/server/src/main/java/server/haengdong/presentation/response/BillResponse.java new file mode 100644 index 000000000..8b79896bb --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/BillResponse.java @@ -0,0 +1,14 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.BillAppResponse; + +public record BillResponse( + Long id, + String title, + Long price, + boolean isFixed +) { + public static BillResponse of(BillAppResponse response) { + return new BillResponse(response.id(), response.title(), response.price(), response.isFixed()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java b/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java index 289cca4fa..b1fe5720b 100644 --- a/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java +++ b/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java @@ -1,13 +1,14 @@ package server.haengdong.presentation.response; import java.util.List; -import server.haengdong.application.response.CurrentMemberAppResponse; +import server.haengdong.application.response.LastBillMemberAppResponse; +import server.haengdong.application.response.MemberAppResponse; -public record CurrentMembersResponse(List<String> memberNames) { +public record CurrentMembersResponse(List<MemberResponse> members) { - public static CurrentMembersResponse of(List<CurrentMemberAppResponse> currentMembers) { - List<String> responses = currentMembers.stream() - .map(CurrentMemberAppResponse::name) + public static CurrentMembersResponse of(List<MemberAppResponse> currentMembers) { + List<MemberResponse> responses = currentMembers.stream() + .map(MemberResponse::of) .toList(); return new CurrentMembersResponse(responses); diff --git a/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java b/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java index c18694393..c03ae8178 100644 --- a/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java +++ b/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java @@ -2,9 +2,12 @@ import server.haengdong.application.response.EventDetailAppResponse; -public record EventDetailResponse(String eventName) { +public record EventDetailResponse( + String eventName, + String account +) { public static EventDetailResponse of(EventDetailAppResponse response) { - return new EventDetailResponse(response.eventName()); + return new EventDetailResponse(response.eventName(), response.account()); } } diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java index 0ea409202..1ab22b83e 100644 --- a/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java +++ b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java @@ -2,9 +2,19 @@ import server.haengdong.application.response.MemberBillReportAppResponse; -public record MemberBillReportResponse(String name, Long price) { +public record MemberBillReportResponse( + Long memberId, + String memberName, + boolean isDeposited, + Long price +) { public static MemberBillReportResponse of(MemberBillReportAppResponse memberBillReportAppResponse) { - return new MemberBillReportResponse(memberBillReportAppResponse.name(), memberBillReportAppResponse.price()); + return new MemberBillReportResponse( + memberBillReportAppResponse.memberId(), + memberBillReportAppResponse.name(), + memberBillReportAppResponse.isDeposited(), + memberBillReportAppResponse.price() + ); } } diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberDepositResponse.java b/server/src/main/java/server/haengdong/presentation/response/MemberDepositResponse.java new file mode 100644 index 000000000..26699bc72 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/MemberDepositResponse.java @@ -0,0 +1,14 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.MemberDepositAppResponse; + +public record MemberDepositResponse( + Long id, + String name, + boolean isDeposited +) { + + public static MemberDepositResponse of(MemberDepositAppResponse response) { + return new MemberDepositResponse(response.id(), response.name(), response.isDeposited()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberResponse.java b/server/src/main/java/server/haengdong/presentation/response/MemberResponse.java new file mode 100644 index 000000000..6b43d72ee --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/MemberResponse.java @@ -0,0 +1,18 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.LastBillMemberAppResponse; +import server.haengdong.application.response.MemberAppResponse; + +public record MemberResponse( + Long id, + String name +) { + + public static MemberResponse of(MemberAppResponse response) { + return new MemberResponse(response.id(), response.name()); + } + + public static MemberResponse of(LastBillMemberAppResponse response) { + return new MemberResponse(response.id(), response.name()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberSaveResponse.java b/server/src/main/java/server/haengdong/presentation/response/MemberSaveResponse.java new file mode 100644 index 000000000..b0740c6ca --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/MemberSaveResponse.java @@ -0,0 +1,12 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.MemberSaveAppResponse; + +public record MemberSaveResponse( + Long id, + String name +) { + public static MemberSaveResponse of(MemberSaveAppResponse response) { + return new MemberSaveResponse(response.id(), response.name()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/MembersResponse.java b/server/src/main/java/server/haengdong/presentation/response/MembersResponse.java index 0947d9e02..333428761 100644 --- a/server/src/main/java/server/haengdong/presentation/response/MembersResponse.java +++ b/server/src/main/java/server/haengdong/presentation/response/MembersResponse.java @@ -1,13 +1,16 @@ package server.haengdong.presentation.response; import java.util.List; -import server.haengdong.application.response.MembersAppResponse; +import server.haengdong.application.response.MemberDepositAppResponse; +import server.haengdong.application.response.MembersDepositAppResponse; public record MembersResponse( - List<String> memberNames + List<MemberDepositResponse> members ) { - public static MembersResponse of(MembersAppResponse response) { - return new MembersResponse(response.memberNames()); + public static MembersResponse of(MembersDepositAppResponse response) { + return new MembersResponse(response.members().stream() + .map(MemberDepositResponse::of) + .toList()); } } diff --git a/server/src/main/java/server/haengdong/presentation/response/MembersSaveResponse.java b/server/src/main/java/server/haengdong/presentation/response/MembersSaveResponse.java new file mode 100644 index 000000000..04e9b133e --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/MembersSaveResponse.java @@ -0,0 +1,16 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import server.haengdong.application.response.MembersSaveAppResponse; + +public record MembersSaveResponse( + List<MemberSaveResponse> members +) { + public static MembersSaveResponse of(MembersSaveAppResponse response) { + return new MembersSaveResponse( + response.members().stream() + .map(MemberSaveResponse::of) + .toList() + ); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/StepResponse.java b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java index 55dd62c58..924651c73 100644 --- a/server/src/main/java/server/haengdong/presentation/response/StepResponse.java +++ b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java @@ -1,27 +1,22 @@ package server.haengdong.presentation.response; -import java.util.ArrayList; import java.util.List; -import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.StepAppResponse; public record StepResponse( - String stepName, - String type, - List<String> members, - List<ActionResponse> actions + List<BillResponse> bills, + List<MemberResponse> members ) { - public static StepResponse of(String stepName, List<String> members, List<ActionAppResponse> actions) { - return new StepResponse( - stepName, - actions.get(0).actionTypeName(), - new ArrayList<>(members), - toActionsResponse(actions) - ); - } + public static StepResponse of(StepAppResponse response) { + List<BillResponse> bills = response.bills().stream() + .map(BillResponse::of) + .toList(); - private static List<ActionResponse> toActionsResponse(List<ActionAppResponse> actions) { - return actions.stream() - .map(ActionResponse::of) + List<MemberResponse> members = response.members().stream() + .map(MemberResponse::of) .toList(); + return new StepResponse(bills, members); + } } + diff --git a/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java b/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java index 5f7573d67..baceeb549 100644 --- a/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java +++ b/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java @@ -1,56 +1,14 @@ package server.haengdong.presentation.response; -import java.util.ArrayList; import java.util.List; -import server.haengdong.application.response.ActionAppResponse; -import server.haengdong.application.response.ActionAppResponse.ActionType; - -public record StepsResponse(List<StepResponse> steps) { - - public static StepsResponse of(List<ActionAppResponse> actions) { - List<StepResponse> steps = new ArrayList<>(); - List<String> currentMembers = new ArrayList<>(); - List<List<ActionAppResponse>> groups = createGroups(actions); - - int billStepCount = 0; - for (List<ActionAppResponse> group : groups) { - changeCurrentMembers(group, currentMembers); - if (group.get(0).actionType() == ActionType.BILL) { - billStepCount++; - } - StepResponse stepResponse = StepResponse.of(billStepCount + "차", currentMembers, group); - steps.add(stepResponse); - } - return new StepsResponse(steps); - } - - private static List<List<ActionAppResponse>> createGroups(List<ActionAppResponse> actions) { - List<List<ActionAppResponse>> groups = new ArrayList<>(); - - for (ActionAppResponse action : actions) { - if (groups.isEmpty() || isActionTypeChange(action, groups)) { - groups.add(new ArrayList<>()); - } - groups.get(groups.size() - 1).add(action); - } - - return groups; - } - - private static boolean isActionTypeChange(ActionAppResponse action, List<List<ActionAppResponse>> groups) { - List<ActionAppResponse> currentGroup = groups.get(groups.size() - 1); - return currentGroup.get(0).actionType() != action.actionType(); - } - - private static void changeCurrentMembers(List<ActionAppResponse> group, List<String> currentMembers) { - for (ActionAppResponse action : group) { - if (action.actionType() == ActionType.IN) { - currentMembers.add(action.name()); - continue; - } - if (action.actionType() == ActionType.OUT) { - currentMembers.remove(action.name()); - } - } +import server.haengdong.application.response.StepAppResponse; + +public record StepsResponse( + List<StepResponse> steps +) { + public static StepsResponse of(List<StepAppResponse> steps) { + return new StepsResponse(steps.stream() + .map(StepResponse::of) + .toList()); } } diff --git a/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java deleted file mode 100644 index c89d057eb..000000000 --- a/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java +++ /dev/null @@ -1,111 +0,0 @@ -package server.haengdong.application; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.assertj.core.api.Assertions.tuple; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import server.haengdong.application.request.BillActionDetailUpdateAppRequest; -import server.haengdong.application.request.BillActionDetailsUpdateAppRequest; -import server.haengdong.application.response.BillActionDetailAppResponse; -import server.haengdong.application.response.BillActionDetailsAppResponse; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.BillActionDetail; -import server.haengdong.domain.action.BillActionDetailRepository; -import server.haengdong.domain.action.BillActionRepository; -import server.haengdong.domain.action.Sequence; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.exception.HaengdongException; -import server.haengdong.support.fixture.Fixture; - -class BillActionDetailServiceTest extends ServiceTestSupport { - - @Autowired - private BillActionDetailService billActionDetailService; - - @Autowired - private EventRepository eventRepository; - - @Autowired - private BillActionRepository billActionRepository; - - @Autowired - private BillActionDetailRepository billActionDetailRepository; - - @DisplayName("참여자별 지출 금액을 조회한다.") - @Test - void findBillActionDetailsTest() { - Event event1 = Fixture.EVENT1; - eventRepository.save(event1); - Sequence sequence = Sequence.createFirst(); - BillAction billAction = new BillAction(event1, sequence, "뽕족", 10000L); - billActionRepository.save(billAction); - BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "토다리", 6000L, true); - BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "쿠키", 4000L, true); - billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); - - BillActionDetailsAppResponse response = billActionDetailService.findBillActionDetails( - event1.getToken(), billAction.getId()); - - assertThat(response.billActionDetailAppResponses()).hasSize(2) - .extracting(BillActionDetailAppResponse::name, BillActionDetailAppResponse::price) - .containsExactly( - tuple("토다리", 6000L), - tuple("쿠키", 4000L) - ); - } - - @DisplayName("지출 금액 수정 요청의 총합이 지출 금액과 일치하지 않으면 예외가 발생한다.") - @Test - void updateBillActionDetailsTest1() { - Event event1 = Fixture.EVENT1; - eventRepository.save(event1); - Sequence sequence = Sequence.createFirst(); - BillAction billAction = new BillAction(event1, sequence, "뽕족", 10000L); - billActionRepository.save(billAction); - BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "토다리", 5000L, false); - BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "쿠키", 5000L, false); - billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); - - BillActionDetailsUpdateAppRequest request = new BillActionDetailsUpdateAppRequest(List.of( - new BillActionDetailUpdateAppRequest("토다리", 3000L, true), - new BillActionDetailUpdateAppRequest("쿠키", 4000L, true) - )); - assertThatCode( - () -> billActionDetailService.updateBillActionDetails(event1.getToken(), billAction.getId(), request)) - .isInstanceOf(HaengdongException.class) - .hasMessage("지출 총액이 일치하지 않습니다."); - } - - @DisplayName("지출 고정 금액을 수정한다.") - @Test - void updateBillActionDetailsTest2() { - Event event1 = Fixture.EVENT1; - eventRepository.save(event1); - Sequence sequence = Sequence.createFirst(); - BillAction billAction = new BillAction(event1, sequence, "뽕족", 10000L); - billActionRepository.save(billAction); - BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "토다리", 5000L, false); - BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "쿠키", 5000L, false); - billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); - - BillActionDetailsUpdateAppRequest request = new BillActionDetailsUpdateAppRequest(List.of( - new BillActionDetailUpdateAppRequest("토다리", 3000L, true), - new BillActionDetailUpdateAppRequest("쿠키", 7000L, true) - )); - billActionDetailService.updateBillActionDetails(event1.getToken(), billAction.getId(), request); - - List<BillActionDetail> results = billActionDetailRepository.findAll(); - - assertThat(results).hasSize(2) - .extracting(BillActionDetail::getMemberName, BillActionDetail::getPrice) - .containsExactly( - tuple("토다리", 3000L), - tuple("쿠키", 7000L) - ); - } -} diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java deleted file mode 100644 index 30675acdd..000000000 --- a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java +++ /dev/null @@ -1,229 +0,0 @@ -package server.haengdong.application; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.assertj.core.api.Assertions.tuple; -import static org.junit.jupiter.api.Assertions.assertAll; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import server.haengdong.application.request.BillActionAppRequest; -import server.haengdong.application.request.BillActionUpdateAppRequest; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.BillActionDetail; -import server.haengdong.domain.action.BillActionDetailRepository; -import server.haengdong.domain.action.BillActionRepository; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionRepository; -import server.haengdong.domain.action.MemberActionStatus; -import server.haengdong.domain.action.Sequence; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.exception.HaengdongException; -import server.haengdong.support.fixture.Fixture; - -class BillActionServiceTest extends ServiceTestSupport { - - @Autowired - private BillActionService billActionService; - - @Autowired - private EventRepository eventRepository; - - @Autowired - private BillActionRepository billActionRepository; - - @Autowired - private BillActionDetailRepository billActionDetailRepository; - - @Autowired - private MemberActionRepository memberActionRepository; - - @DisplayName("지출 내역을 생성한다.") - @Test - void saveAllBillAction() { - Event event = Fixture.EVENT1; - Event savedEvent = eventRepository.save(event); - Sequence sequence1 = Sequence.createFirst(); - Sequence sequence2 = sequence1.next(); - MemberAction memberAction1 = new MemberAction(event, sequence1, "백호", MemberActionStatus.IN); - MemberAction memberAction2 = new MemberAction(event, sequence2, "망쵸", MemberActionStatus.IN); - memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); - - List<BillActionAppRequest> requests = List.of( - new BillActionAppRequest("뽕족", 10_000L), - new BillActionAppRequest("인생맥주", 15_000L) - ); - - billActionService.saveAllBillAction(event.getToken(), requests); - - List<BillAction> actions = billActionRepository.findByEvent(savedEvent); - - assertThat(actions).extracting(BillAction::getTitle, BillAction::getPrice, BillAction::getSequence) - .containsExactlyInAnyOrder( - tuple("뽕족", 10_000L, new Sequence(3L)), - tuple("인생맥주", 15_000L, new Sequence(4L)) - ); - } - - @DisplayName("지출 내역을 생성하면 지출 상세 내역이 생성된다.") - @Test - void saveAllBillActionTest1() { - Event event = Fixture.EVENT1; - Event savedEvent = eventRepository.save(event); - Sequence sequence1 = Sequence.createFirst(); - Sequence sequence2 = sequence1.next(); - MemberAction memberAction1 = new MemberAction(event, sequence1, "백호", MemberActionStatus.IN); - MemberAction memberAction2 = new MemberAction(event, sequence2, "망쵸", MemberActionStatus.IN); - memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); - - List<BillActionAppRequest> request = List.of( - new BillActionAppRequest("뽕족", 10_000L), - new BillActionAppRequest("인생맥주", 15_000L) - ); - - billActionService.saveAllBillAction(event.getToken(), request); - - List<BillActionDetail> billActionDetails = billActionDetailRepository.findAll(); - - assertThat(billActionDetails) - .hasSize(4) - .extracting("memberName", "price") - .containsExactlyInAnyOrder( - tuple("백호", 5_000L), - tuple("망쵸", 5_000L), - tuple("백호", 7_500L), - tuple("망쵸", 7_500L) - ); - } - - @DisplayName("이벤트가 존재하지 않으면 지출 내역을 생성할 수 없다.") - @Test - void saveAllBillAction1() { - List<BillActionAppRequest> requests = List.of( - new BillActionAppRequest("뽕족", 10_000L), - new BillActionAppRequest("인생맥주", 15_000L) - ); - - assertThatThrownBy(() -> billActionService.saveAllBillAction("token", requests)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("지출 액션을 수정한다.") - @Test - void updateBillAction() { - Event event = Fixture.EVENT1; - Event savedEvent = eventRepository.save(event); - Sequence sequence = Sequence.createFirst(); - BillAction billAction = new BillAction(event, sequence, "뽕족", 10_000L); - BillAction savedBillAction = billActionRepository.save(billAction); - - Long actionId = savedBillAction.getId(); - BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L); - - billActionService.updateBillAction(event.getToken(), actionId, request); - - BillAction updatedBillAction = billActionRepository.findById(savedBillAction.getId()).get(); - - assertAll( - () -> assertThat(updatedBillAction.getTitle()).isEqualTo("인생맥주"), - () -> assertThat(updatedBillAction.getPrice()).isEqualTo(20_000L) - ); - } - - @DisplayName("행사에 속하지 않은 지출 액션은 수정할 수 없다.") - @Test - void updateBillAction1() { - Event event1 = Fixture.EVENT1; - Event event2 = Fixture.EVENT2; - Event savedEvent1 = eventRepository.save(event1); - Event savedEvent2 = eventRepository.save(event2); - Sequence sequence1 = Sequence.createFirst(); - Sequence sequence2 = Sequence.createFirst(); - BillAction billAction1 = new BillAction(event1, sequence1, "뽕족", 10_000L); - BillAction billAction2 = new BillAction(event2, sequence2, "뽕족", 10_000L); - BillAction savedBillAction1 = billActionRepository.save(billAction1); - billActionRepository.save(billAction2); - - Long actionId = savedBillAction1.getId(); - BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L); - - assertThatThrownBy(() -> billActionService.updateBillAction(event2.getToken(), actionId, request)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("지출 내역 금액을 변경하면 지출 디테일이 초기화 된다.") - @Test - void updateBillAction2() { - Event event = Fixture.EVENT1; - Event savedEvent = eventRepository.save(event); - Sequence sequence = Sequence.createFirst(); - BillAction billAction = new BillAction(event, sequence, "뽕족", 10_000L); - BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "감자", 3000L, true); - BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "고구마", 2000L, true); - BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "당근", 3000L, true); - BillActionDetail billActionDetail4 = new BillActionDetail(billAction, "양파", 2000L, true); - billAction.addDetails(List.of(billActionDetail1, billActionDetail2, billActionDetail3, billActionDetail4)); - BillAction savedBillAction = billActionRepository.save(billAction); - - Long actionId = savedBillAction.getId(); - BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L); - - billActionService.updateBillAction(event.getToken(), actionId, request); - - BillAction updatedBillAction = billActionRepository.findById(savedBillAction.getId()).get(); - List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(updatedBillAction); - - assertThat(billActionDetails).hasSize(4) - .extracting("memberName", "price") - .containsExactlyInAnyOrder( - tuple("감자", 5000L), - tuple("고구마", 5000L), - tuple("당근", 5000L), - tuple("양파", 5000L) - ); - } - - @DisplayName("지출 내역을 삭제한다.") - @Test - void deleteBillAction() { - Event event = Fixture.EVENT1; - eventRepository.save(event); - BillAction billAction = Fixture.createBillAction(event, 1L, "커피", 50_900L); - billActionRepository.save(billAction); - Long actionId = billAction.getId(); - - billActionService.deleteBillAction(event.getToken(), actionId); - - assertThat(billActionRepository.findById(billAction.getId())).isEmpty(); - } - - @DisplayName("지출 내역을 삭제하면 지출 상세도 삭제된다.") - @Test - void deleteBillActionTest1() { - Event event = Fixture.EVENT1; - eventRepository.save(event); - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "백호", MemberActionStatus.IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "망쵸", MemberActionStatus.IN); - BillAction billAction = Fixture.createBillAction(event, 3L, "커피", 50_900L); - BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "백호", 25_450L, false); - BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "망쵸", 25_450L, false); - memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); - billActionRepository.save(billAction); - billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); - Long actionId = billAction.getId(); - - billActionService.deleteBillAction(event.getToken(), actionId); - - assertThat(billActionDetailRepository.findAll()).isEmpty(); - } - - @DisplayName("지출 내역 삭제 시 행사가 존재하지 않으면 예외가 발생한다.") - @Test - void deleteBillAction1() { - assertThatThrownBy(() -> billActionService.deleteBillAction("소하망쵸", 1L)) - .isInstanceOf(HaengdongException.class); - } -} diff --git a/server/src/test/java/server/haengdong/application/BillServiceTest.java b/server/src/test/java/server/haengdong/application/BillServiceTest.java new file mode 100644 index 000000000..72fd0192f --- /dev/null +++ b/server/src/test/java/server/haengdong/application/BillServiceTest.java @@ -0,0 +1,308 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; +import static org.junit.jupiter.api.Assertions.assertAll; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import server.haengdong.application.request.BillAppRequest; +import server.haengdong.application.request.BillDetailUpdateAppRequest; +import server.haengdong.application.request.BillDetailsUpdateAppRequest; +import server.haengdong.application.request.BillUpdateAppRequest; +import server.haengdong.application.response.BillAppResponse; +import server.haengdong.application.response.BillDetailAppResponse; +import server.haengdong.application.response.BillDetailsAppResponse; +import server.haengdong.application.response.MemberAppResponse; +import server.haengdong.application.response.StepAppResponse; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.bill.BillDetail; +import server.haengdong.domain.bill.BillDetailRepository; +import server.haengdong.domain.bill.BillRepository; +import server.haengdong.domain.member.Member; +import server.haengdong.domain.member.MemberRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class BillServiceTest extends ServiceTestSupport { + + @Autowired + private BillService billService; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillRepository billRepository; + + @Autowired + private BillDetailRepository billDetailRepository; + + @Autowired + private MemberRepository memberRepository; + + @DisplayName("전체 지출 내역을 조회한다.") + @Test + void findSteps() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + Member member = new Member(event, "토다리"); + memberRepository.save(member); + Bill bill = Bill.create(event, "행동대장 회식", 100000L, List.of(member)); + billRepository.save(bill); + + List<StepAppResponse> steps = billService.findSteps(event.getToken()); + + assertThat(steps.get(0).bills()).hasSize(1) + .extracting(BillAppResponse::id, BillAppResponse::title, BillAppResponse::price, + BillAppResponse::isFixed) + .containsExactlyInAnyOrder( + tuple(bill.getId(), bill.getTitle(), bill.getPrice(), bill.isFixed()) + ); + + assertThat(steps.get(0).members()).hasSize(1) + .extracting(MemberAppResponse::id, MemberAppResponse::name) + .containsExactlyInAnyOrder( + tuple(member.getId(), member.getName()) + ); + } + + @DisplayName("지출 내역을 생성한다.") + @Test + void saveBill() { + Event event = Fixture.EVENT1; + Event savedEvent = eventRepository.save(event); + + Member member1 = Fixture.MEMBER1; + Member member2 = Fixture.MEMBER2; + memberRepository.saveAll(List.of(member1, member2)); + List<Long> memberIds = List.of(member1.getId(), member2.getId()); + BillAppRequest billAppRequest = new BillAppRequest("뽕족", 10_000L, memberIds); + + billService.saveBill(event.getToken(), billAppRequest); + + List<Bill> bills = billRepository.findAllByEvent(savedEvent); + + assertThat(bills).extracting(Bill::getTitle, Bill::getPrice) + .containsExactlyInAnyOrder( + tuple("뽕족", 10_000L) + ); + } + + @DisplayName("지출 내역을 생성하면 지출 상세 내역이 생성된다.") + @Test + void saveBillTest1() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + + Member member1 = Fixture.MEMBER1; + Member member2 = Fixture.MEMBER2; + List<Member> members = List.of(member1, member2); + memberRepository.saveAll(members); + + BillAppRequest request = new BillAppRequest("뽕족", 10_000L, List.of(member1.getId(), member2.getId())); + + billService.saveBill(event.getToken(), request); + + List<BillDetail> billDetails = billDetailRepository.findAllByBillId(1L); + + assertThat(billDetails) + .hasSize(2) + .extracting("member", "price") + .containsExactlyInAnyOrder( + tuple(member1, 5_000L), + tuple(member2, 5_000L) + ); + } + + @DisplayName("토큰에 해당하는 이벤트가 존재하지 않으면 지출 내역을 생성할 수 없다.") + @Test + void saveBill1() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + + Member member1 = Fixture.MEMBER1; + Member member2 = Fixture.MEMBER2; + List<Member> members = List.of(member1, member2); + memberRepository.saveAll(members); + + BillAppRequest request = new BillAppRequest("뽕족", 10_000L, List.of(member1.getId(), member2.getId())); + + assertThatThrownBy(() -> billService.saveBill("wrongToken", request)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("지출을 수정한다.") + @Test + void updateBill() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + + Bill bill = new Bill(event, "뽕족", 10_000L); + Bill savedBill = billRepository.save(bill); + + Long billId = savedBill.getId(); + BillUpdateAppRequest request = new BillUpdateAppRequest("인생맥주", 20_000L); + + billService.updateBill(event.getToken(), billId, request); + + Bill updatedBill = billRepository.findById(savedBill.getId()).get(); + + assertAll( + () -> assertThat(updatedBill.getTitle()).isEqualTo("인생맥주"), + () -> assertThat(updatedBill.getPrice()).isEqualTo(20_000L) + ); + } + + @DisplayName("행사에 속하지 않은 지출은 수정할 수 없다.") + @Test + void updateBill1() { + Event event1 = Fixture.EVENT1; + Event event2 = Fixture.EVENT2; + eventRepository.saveAll(List.of(event1, event2)); + Bill bill1 = new Bill(event1, "뽕족", 10_000L); + Bill bill2 = new Bill(event2, "뽕족", 10_000L); + Bill savedBill1 = billRepository.save(bill1); + billRepository.save(bill2); + + Long bill1Id = savedBill1.getId(); + BillUpdateAppRequest request = new BillUpdateAppRequest("인생맥주", 20_000L); + + assertThatThrownBy(() -> billService.updateBill(event2.getToken(), bill1Id, request)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("지출 내역 금액을 변경하면 지출 디테일이 초기화 된다.") + @Test + void updateBill2() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + Member member1 = new Member(event, "감자"); + Member member2 = new Member(event, "고구마"); + Member member3 = new Member(event, "당근"); + Member member4 = new Member(event, "양파"); + List<Member> members = List.of(member1, member2, member3, member4); + memberRepository.saveAll(members); + Bill bill = Bill.create(event, "뽕족", 10_000L, members); + bill.getBillDetails().forEach(billDetail -> billDetail.updateIsFixed(true)); + billRepository.save(bill); + BillUpdateAppRequest request = new BillUpdateAppRequest("인생맥주", 20_000L); + + billService.updateBill(event.getToken(), bill.getId(), request); + + Bill updatedBill = billRepository.findById(bill.getId()).get(); + List<BillDetail> billDetails = billDetailRepository.findAllByBill(updatedBill); + + assertThat(billDetails).hasSize(4) + .extracting(BillDetail::getPrice) + .containsExactly(5000L, 5000L, 5000L, 5000L); + } + + @DisplayName("지출 내역을 삭제한다.") + @Test + void deleteBill() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + Member member1 = new Member(event, "토다리"); + Member member2 = new Member(event, "쿠키"); + memberRepository.saveAll(List.of(member1, member2)); + + Bill bill = Bill.create(event, "뽕족", 10000L, List.of(member1, member2)); + billRepository.save(bill); + Long billId = bill.getId(); + + billService.deleteBill(event.getToken(), billId); + + assertThat(billRepository.findById(billId)).isEmpty(); + } + + @DisplayName("지출 내역 삭제 시 행사가 존재하지 않으면 예외가 발생한다.") + @Test + void deleteBill1() { + assertThatThrownBy(() -> billService.deleteBill("소하망쵸", 1L)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("지출 금액 수정 요청의 총합이 지출 금액과 일치하지 않으면 예외가 발생한다.") + @Test + void updateBillDetailsTest1() { + Event event1 = Fixture.EVENT1; + eventRepository.save(event1); + Member member1 = new Member(event1, "토다리"); + Member member2 = new Member(event1, "쿠키"); + memberRepository.saveAll(List.of(member1, member2)); + + Bill bill = Bill.create(event1, "뽕족", 10000L, List.of(member1, member2)); + billRepository.save(bill); + List<BillDetail> billDetails = bill.getBillDetails(); + + BillDetailsUpdateAppRequest request = new BillDetailsUpdateAppRequest(List.of( + new BillDetailUpdateAppRequest(billDetails.get(0).getId(), 3000L, true), + new BillDetailUpdateAppRequest(billDetails.get(1).getId(), 4000L, true) + )); + + assertThatThrownBy( + () -> billService.updateBillDetails(event1.getToken(), bill.getId(), request)) + .isInstanceOf(HaengdongException.class) + .hasMessage("지출 총액이 일치하지 않습니다."); + } + + @DisplayName("지출 고정 금액을 수정한다.") + @Test + void updateBillDetailsTest2() { + Event event1 = Fixture.EVENT1; + eventRepository.save(event1); + Member member1 = new Member(event1, "토다리"); + Member member2 = new Member(event1, "쿠키"); + memberRepository.saveAll(List.of(member1, member2)); + + Bill bill = Bill.create(event1, "뽕족", 10000L, List.of(member1, member2)); + billRepository.save(bill); + List<BillDetail> billDetails = bill.getBillDetails(); + + BillDetailsUpdateAppRequest request = new BillDetailsUpdateAppRequest(List.of( + new BillDetailUpdateAppRequest(billDetails.get(0).getId(), 3000L, true), + new BillDetailUpdateAppRequest(billDetails.get(1).getId(), 7000L, true) + )); + + billService.updateBillDetails(event1.getToken(), bill.getId(), request); + + List<BillDetail> foundBillDetails = billDetailRepository.findAllByBill(bill); + + assertThat(foundBillDetails).hasSize(2) + .extracting(BillDetail::getId, BillDetail::getPrice) + .containsExactly( + tuple(billDetails.get(0).getId(), 3000L), + tuple(billDetails.get(1).getId(), 7000L) + ); + } + + @DisplayName("참여자별 지출 금액을 조회한다.") + @Test + void findBillDetailsTest() { + Event event1 = Fixture.EVENT1; + eventRepository.save(event1); + + Member member1 = Fixture.MEMBER1; + Member member2 = Fixture.MEMBER2; + List<Member> members = List.of(member1, member2); + memberRepository.saveAll(members); + + Bill bill = Bill.create(event1, "뽕족", 10000L, members); + billRepository.save(bill); + + BillDetailsAppResponse response = billService.findBillDetails(event1.getToken(), bill.getId()); + + assertThat(response.billDetails()).hasSize(2) + .extracting(BillDetailAppResponse::memberName, BillDetailAppResponse::price) + .containsExactly( + tuple("토다리", 5000L), + tuple("쿠키", 5000L) + ); + } +} diff --git a/server/src/test/java/server/haengdong/application/EventServiceTest.java b/server/src/test/java/server/haengdong/application/EventServiceTest.java index 37e6372a8..e5fef4184 100644 --- a/server/src/test/java/server/haengdong/application/EventServiceTest.java +++ b/server/src/test/java/server/haengdong/application/EventServiceTest.java @@ -2,12 +2,9 @@ import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.assertj.core.api.Assertions.tuple; +import static org.assertj.core.api.AssertionsForClassTypes.tuple; +import static org.junit.jupiter.api.Assertions.assertAll; import static org.mockito.BDDMockito.given; -import static server.haengdong.domain.action.MemberActionStatus.IN; -import static server.haengdong.domain.action.MemberActionStatus.OUT; -import static server.haengdong.support.fixture.Fixture.BILL_ACTION; import java.util.List; import org.junit.jupiter.api.DisplayName; @@ -15,24 +12,17 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.MockBean; import server.haengdong.application.request.EventAppRequest; -import server.haengdong.application.request.MemberNameUpdateAppRequest; -import server.haengdong.application.request.MemberNamesUpdateAppRequest; -import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.request.EventUpdateAppRequest; import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; import server.haengdong.application.response.MemberBillReportAppResponse; -import server.haengdong.application.response.MembersAppResponse; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.BillActionDetail; -import server.haengdong.domain.action.BillActionRepository; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionRepository; -import server.haengdong.domain.action.Sequence; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.bill.BillRepository; +import server.haengdong.domain.member.Member; +import server.haengdong.domain.member.MemberRepository; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.domain.event.EventTokenProvider; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; import server.haengdong.support.fixture.Fixture; class EventServiceTest extends ServiceTestSupport { @@ -44,10 +34,10 @@ class EventServiceTest extends ServiceTestSupport { private EventRepository eventRepository; @Autowired - private BillActionRepository billActionRepository; + private BillRepository billRepository; @Autowired - private MemberActionRepository memberActionRepository; + private MemberRepository memberRepository; @MockBean private EventTokenProvider eventTokenProvider; @@ -74,156 +64,68 @@ void findEventTest() { assertThat(eventDetailAppResponse.eventName()).isEqualTo(event.getName()); } - @DisplayName("행사에 속한 모든 액션을 조회한다.") + @DisplayName("행사 정보를 수정한다.") @Test - void findActionsTest() { - Event event = Fixture.EVENT1; - MemberAction memberAction = Fixture.createMemberAction(event, 1L, "토다리", IN); - MemberAction memberAction1 = Fixture.createMemberAction(event, 2L, "쿠키", IN); - BillAction billAction = Fixture.createBillAction(event, 3L, "뽕나무쟁이족발", 30000L); - eventRepository.save(event); - memberActionRepository.saveAll(List.of(memberAction, memberAction1)); - billActionRepository.save(billAction); - - List<ActionAppResponse> actionAppResponses = eventService.findActions(event.getToken()); - - assertThat(actionAppResponses).hasSize(3) - .extracting(ActionAppResponse::actionId, - ActionAppResponse::name, - ActionAppResponse::price, - ActionAppResponse::sequence, - ActionAppResponse::actionTypeName) - .containsExactly( - tuple(1L, "토다리", null, 1L, "IN"), - tuple(2L, "쿠키", null, 2L, "IN"), - tuple(1L, "뽕나무쟁이족발", 30000L, 3L, "BILL") - ); - } - - @DisplayName("행사에 참여한 전체 인원을 중복 없이 조회한다.") - @Test - void findAllMembersTest() { - Event event = Fixture.EVENT1; - BillAction billAction = Fixture.createBillAction(event, 3L, "뽕나무쟁이족발", 30000L); - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "쿠키", IN); - MemberAction memberAction3 = Fixture.createMemberAction(event, 4L, "쿠키", OUT); - eventRepository.save(event); - billActionRepository.save(billAction); - memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); - - MembersAppResponse membersAppResponse = eventService.findAllMembers(event.getToken()); - - assertThat(membersAppResponse.memberNames()).containsExactlyInAnyOrder("토다리", "쿠키"); - } - - @DisplayName("행사 참여 인원들의 이름을 변경한다.") - @Test - void updateMember() { - Event event = Fixture.EVENT1; - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "쿠키", IN); - MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "웨디", IN); - MemberAction memberAction4 = Fixture.createMemberAction(event, 4L, "쿠키", OUT); - MemberAction memberAction5 = Fixture.createMemberAction(event, 5L, "쿠키", IN); - MemberAction memberAction6 = Fixture.createMemberAction(event, 6L, "쿠키", OUT); - eventRepository.save(event); - memberActionRepository.saveAll(List.of( - memberAction1, memberAction2, memberAction3, memberAction4, memberAction5, memberAction6 - )); - - eventService.updateMember(event.getToken(), new MemberNamesUpdateAppRequest(List.of( - new MemberNameUpdateAppRequest("쿠키", "쿡쿡"), - new MemberNameUpdateAppRequest("토다리", "토쟁이") - ))); - - List<MemberAction> foundMemberActions = memberActionRepository.findAllByEvent(event); - assertThat(foundMemberActions) - .extracting(MemberAction::getId, MemberAction::getMemberName) - .contains( - tuple(memberAction1.getId(), "토쟁이"), - tuple(memberAction2.getId(), "쿡쿡"), - tuple(memberAction3.getId(), "웨디"), - tuple(memberAction4.getId(), "쿡쿡"), - tuple(memberAction5.getId(), "쿡쿡"), - tuple(memberAction6.getId(), "쿡쿡") - ); - } - - @DisplayName("이미 존재하는 인원의 이름으로 변경할 수 없다.") - @Test - void updateMember1() { - Event event = Fixture.EVENT1; - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "쿠키", IN); - MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "웨디", IN); + void updateEventTest() { + Event event = new Event("행동대장 비대위", "1234", "token"); eventRepository.save(event); - memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); - MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( - new MemberNameUpdateAppRequest("쿠키", "쿡쿡"), - new MemberNameUpdateAppRequest("웨디", "토다리") - )); + EventUpdateAppRequest eventUpdateAppRequest = new EventUpdateAppRequest("새로운 행사 이름", "토스뱅크", "12345678"); + eventService.updateEvent(event.getToken(), eventUpdateAppRequest); - assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) - .isInstanceOf(HaengdongException.class); + Event updateEvent = eventRepository.findByToken(event.getToken()).get(); + assertAll( + () -> assertThat(updateEvent.getName()).isEqualTo("새로운 행사 이름"), + () -> assertThat(updateEvent.getAccount()).isEqualTo("토스뱅크 12345678") + ); } - @DisplayName("존재하지 않는 인원은 변경할 수 없다.") + @DisplayName("행사의 은행 정보만 수정한다.") @Test - void updateMember2() { - Event event = Fixture.EVENT1; - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "쿠키", IN); - MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "웨디", IN); + void updateEventTest1() { + Event event = new Event("행동대장 비대위", "1234", "token"); eventRepository.save(event); - memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); - MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( - new MemberNameUpdateAppRequest("쿡쿡", "토쟁이"), - new MemberNameUpdateAppRequest("웨디", "말복") - )); + EventUpdateAppRequest eventUpdateAppRequest = new EventUpdateAppRequest(null, "토스뱅크", "12345678"); + eventService.updateEvent(event.getToken(), eventUpdateAppRequest); - assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) - .isInstanceOf(HaengdongException.class); + Event updateEvent = eventRepository.findByToken(event.getToken()).get(); + assertAll( + () -> assertThat(updateEvent.getName()).isEqualTo("행동대장 비대위"), + () -> assertThat(updateEvent.getAccount()).isEqualTo("토스뱅크 12345678") + ); } - @DisplayName("변경 전 참여 인원 이름이 중복될 수 없다.") + @DisplayName("행사의 이름만 수정한다.") @Test - void updateMember3() { - Event event = Fixture.EVENT1; - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "쿠키", IN); - MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "웨디", IN); + void updateEventTest2() { + Event event = new Event("행동대장 비대위", "1234", "token"); eventRepository.save(event); - memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); - MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( - new MemberNameUpdateAppRequest("쿠키", "쿡쿡"), - new MemberNameUpdateAppRequest("쿠키", "토쟁이") - )); + EventUpdateAppRequest eventUpdateAppRequest = new EventUpdateAppRequest("행동대장 정상 영업", null, null); + eventService.updateEvent(event.getToken(), eventUpdateAppRequest); - assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) - .isInstanceOf(HaengdongException.class); + Event updateEvent = eventRepository.findByToken(event.getToken()).get(); + assertAll( + () -> assertThat(updateEvent.getName()).isEqualTo("행동대장 정상 영업"), + () -> assertThat(updateEvent.getAccount()).isEqualTo("") + ); } - @DisplayName("변경 후 참여 인원 이름이 중복될 수 없다.") + @DisplayName("행사의 계좌 정보 일부가 누락되면 변경하지 않는다.") @Test - void updateMember4() { - Event event = Fixture.EVENT1; - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "쿠키", IN); - MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "웨디", IN); + void updateEventTest3() { + Event event = new Event("행동대장 비대위", "1234", "token"); eventRepository.save(event); - memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); - MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( - new MemberNameUpdateAppRequest("쿠키", "쿡쿡"), - new MemberNameUpdateAppRequest("토다리", "쿡쿡") - )); + EventUpdateAppRequest eventUpdateAppRequest = new EventUpdateAppRequest(null, "망쵸뱅크", null); + eventService.updateEvent(event.getToken(), eventUpdateAppRequest); - assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) - .isInstanceOf(HaengdongException.class); + Event updateEvent = eventRepository.findByToken(event.getToken()).get(); + assertAll( + () -> assertThat(updateEvent.getName()).isEqualTo("행동대장 비대위"), + () -> assertThat(updateEvent.getAccount()).isEqualTo("") + ); } @DisplayName("참여자별 정산 현황을 조회한다.") @@ -231,49 +133,29 @@ void updateMember4() { void getMemberBillReports() { Event event = Fixture.EVENT1; Event savedEvent = eventRepository.save(event); - List<MemberAction> memberActions = List.of( - new MemberAction(savedEvent, new Sequence(1L), "소하", IN), - new MemberAction(savedEvent, new Sequence(2L), "감자", IN), - new MemberAction(savedEvent, new Sequence(3L), "쿠키", IN), - new MemberAction(savedEvent, new Sequence(5L), "감자", OUT) - ); - List<BillAction> billActions = List.of( - new BillAction(savedEvent, new Sequence(4L), "뽕족", 60_000L), - new BillAction(savedEvent, new Sequence(7L), "인생네컷", 20_000L) + List<Member> members = List.of( + new Member(savedEvent, "소하"), + new Member(savedEvent, "감자"), + new Member(savedEvent, "쿠키"), + new Member(savedEvent, "고구마") ); - billActions.get(0).addDetails( - List.of( - new BillActionDetail(BILL_ACTION, "소하", 10_000L, false), - new BillActionDetail(BILL_ACTION, "감자", 40_000L, true), - new BillActionDetail(BILL_ACTION, "쿠키", 10_000L, false) - ) + memberRepository.saveAll(members); + List<Bill> bills = List.of( + Bill.create(savedEvent, "뽕족", 60_000L, members), + Bill.create(savedEvent, "인생네컷", 20_000L, members) ); - billActions.get(1).addDetails( - List.of( - new BillActionDetail(BILL_ACTION, "소하", 5_000L, true), - new BillActionDetail(BILL_ACTION, "쿠키", 15_000L, true) - ) - ); - memberActionRepository.saveAll(memberActions); - billActionRepository.saveAll(billActions); + billRepository.saveAll(bills); List<MemberBillReportAppResponse> responses = eventService.getMemberBillReports(event.getToken()); assertThat(responses) - .hasSize(3) + .hasSize(4) .extracting(MemberBillReportAppResponse::name, MemberBillReportAppResponse::price) .containsExactlyInAnyOrder( - tuple("감자", 40_000L), - tuple("쿠키", 25_000L), - tuple("소하", 15_000L) + tuple("감자", 20_000L), + tuple("쿠키", 20_000L), + tuple("소하", 20_000L), + tuple("고구마", 20_000L) ); } - - @DisplayName("존재하지 않는 이벤트의 참여자별 정산 현황을 조회하는 경우 예외가 발생한다.") - @Test - void getMemberBillReports1() { - assertThatThrownBy(() -> eventService.getMemberBillReports("invalid token")) - .isInstanceOf(HaengdongException.class) - .hasMessage(HaengdongErrorCode.EVENT_NOT_FOUND.getMessage()); - } } diff --git a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java deleted file mode 100644 index 4f1156714..000000000 --- a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java +++ /dev/null @@ -1,216 +0,0 @@ -package server.haengdong.application; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.assertj.core.api.Assertions.tuple; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import server.haengdong.application.request.MemberActionSaveAppRequest; -import server.haengdong.application.request.MemberActionsSaveAppRequest; -import server.haengdong.domain.action.CurrentMembers; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionRepository; -import server.haengdong.domain.action.MemberActionStatus; -import server.haengdong.domain.action.Sequence; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.exception.HaengdongException; -import server.haengdong.support.fixture.Fixture; - -class MemberActionFactoryTest extends ServiceTestSupport { - - @Autowired - private MemberActionFactory memberActionFactory; - - @Autowired - private MemberActionRepository memberActionRepository; - - @Autowired - private EventRepository eventRepository; - - @DisplayName("이전 멤버 액션이 시퀀스 기준으로 정렬되지 않은 상태에서 새로운 멤버 액션 요청을 검증한다.") - @Test - void createMemberActionsTest() { - Event event = eventRepository.save(Fixture.EVENT1); - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", MemberActionStatus.IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "토다리", MemberActionStatus.OUT); - memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); - - List<MemberAction> unorderedMemberActions = List.of(memberAction2, memberAction1); - CurrentMembers currentMembers = CurrentMembers.of(unorderedMemberActions); - Sequence sequence = new Sequence(3L); - - assertThatThrownBy(() -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("인원 변동 액션을 생성한다.") - @Test - void createMemberActionsTest1() { - Event event = eventRepository.save(Fixture.EVENT1); - MemberAction memberAction = Fixture.createMemberAction(event, 1L, "토다리", MemberActionStatus.IN); - memberActionRepository.save(memberAction); - - MemberActionsSaveAppRequest memberActionsSaveAppRequest = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); - Sequence sequence = new Sequence(2L); - - CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); - List<MemberAction> memberActions = memberActionFactory.createMemberActions(event, memberActionsSaveAppRequest, - currentMembers, sequence - ); - - assertThat(memberActions).hasSize(1) - .extracting(MemberAction::getEvent, MemberAction::getSequence, MemberAction::getMemberName, - MemberAction::getStatus) - .containsExactly( - tuple(event, sequence, "토다리", MemberActionStatus.OUT) - ); - } - - @DisplayName("현재 행사에 참여 중인 경우에 퇴장할 수 있다.") - @Test - void createMemberActionsTest2() { - Event event = eventRepository.save(Fixture.EVENT1); - MemberAction memberAction = Fixture.createMemberAction(event, 1L, "토다리", MemberActionStatus.IN); - memberActionRepository.save(memberAction); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); - Sequence sequence = new Sequence(2L); - CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); - - assertThatCode(() -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence)) - .doesNotThrowAnyException(); - } - - @DisplayName("행사에서 퇴장한 경우에 입장할 수 있다.") - @Test - void createMemberActionsTest3() { - Event event = eventRepository.save(Fixture.EVENT1); - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", MemberActionStatus.IN); - memberActionRepository.save(memberAction1); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "토다리", MemberActionStatus.OUT); - memberActionRepository.save(memberAction2); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("토다리", "IN"))); - Sequence sequence = new Sequence(3L); - CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction1, memberAction2)); - - assertThatCode(() -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence)) - .doesNotThrowAnyException(); - } - - @DisplayName("행사에 입장한 적 없는 경우에 입장할 수 있다.") - @Test - void createMemberActionsTest4() { - Event event = eventRepository.save(Fixture.EVENT1); - MemberAction memberAction = Fixture.createMemberAction(event, 1L, "토다리", MemberActionStatus.IN); - memberActionRepository.save(memberAction); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); - Sequence sequence = new Sequence(2L); - CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); - - assertThatCode(() -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence)) - .doesNotThrowAnyException(); - } - - @DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다.") - @Test - void createMemberActionTest5() { - Event event = eventRepository.save(Fixture.EVENT1); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("쿠키", "OUT"))); - Sequence sequence = new Sequence(2L); - CurrentMembers currentMembers = CurrentMembers.of(List.of()); - - assertThatCode( - () -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("행사에 이미 참여 중인 경우 다시 입장할 수 없다.") - @Test - void createMemberActionTest6() { - Event event = eventRepository.save(Fixture.EVENT1); - MemberAction memberAction = Fixture.createMemberAction(event, 1L, "쿠키", MemberActionStatus.IN); - memberActionRepository.save(memberAction); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); - Sequence sequence = new Sequence(2L); - CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); - - assertThatCode(() -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("한 명의 사용자는 동시에 여러 번 입장할 수 없다.") - @Test - void createMemberActionTest7() { - Event event = eventRepository.save(Fixture.EVENT1); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of( - new MemberActionSaveAppRequest("쿠키", "IN"), - new MemberActionSaveAppRequest("쿠키", "IN") - )); - Sequence sequence = new Sequence(1L); - CurrentMembers currentMembers = CurrentMembers.of(List.of()); - - assertThatCode( - () -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("한 명의 사용자는 동시에 여러 번 퇴장할 수 없다.") - @Test - void createMemberActionTest8() { - Event event = eventRepository.save(Fixture.EVENT1); - Sequence sequence1 = new Sequence(1L); - MemberAction memberAction = new MemberAction(event, sequence1, "쿠키", MemberActionStatus.IN); - memberActionRepository.save(memberAction); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of( - new MemberActionSaveAppRequest("쿠키", "OUT"), - new MemberActionSaveAppRequest("쿠키", "OUT") - )); - Sequence sequence2 = new Sequence(2L); - CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); - - assertThatCode(() -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence2)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("한 명의 사용자는 입장과 퇴장을 동시에 할 수 없다.") - @Test - void createMemberActionTest9() { - Event event = eventRepository.save(Fixture.EVENT1); - Sequence sequence = new Sequence(1L); - MemberAction memberAction = new MemberAction(event, sequence, "쿠키", MemberActionStatus.IN); - memberActionRepository.save(memberAction); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of( - new MemberActionSaveAppRequest("쿠키", "IN"), - new MemberActionSaveAppRequest("쿠키", "OUT") - )); - Sequence sequence2 = new Sequence(2L); - CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); - - assertThatCode(() -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence2)) - .isInstanceOf(HaengdongException.class); - } -} diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java deleted file mode 100644 index 51f5428f0..000000000 --- a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java +++ /dev/null @@ -1,231 +0,0 @@ -package server.haengdong.application; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.assertj.core.groups.Tuple.tuple; -import static server.haengdong.domain.action.MemberActionStatus.IN; -import static server.haengdong.domain.action.MemberActionStatus.OUT; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import server.haengdong.application.request.MemberActionSaveAppRequest; -import server.haengdong.application.request.MemberActionsSaveAppRequest; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.BillActionDetail; -import server.haengdong.domain.action.BillActionDetailRepository; -import server.haengdong.domain.action.BillActionRepository; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionRepository; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.exception.HaengdongException; -import server.haengdong.support.fixture.Fixture; - -class MemberActionServiceTest extends ServiceTestSupport { - - @Autowired - private MemberActionService memberActionService; - - @Autowired - private MemberActionRepository memberActionRepository; - - @Autowired - private EventRepository eventRepository; - - @Autowired - private BillActionRepository billActionRepository; - - @Autowired - private BillActionDetailRepository billActionDetailRepository; - - @DisplayName("현재 행사에 참여하고 있는 경우에 나갈 수 있다.") - @Test - void saveMemberActionTest() { - Event event = eventRepository.save(Fixture.EVENT1); - MemberAction memberAction = Fixture.createMemberAction(event, 1L, "망쵸", IN); - memberActionRepository.save(memberAction); - - assertThatCode(() -> memberActionService.saveMemberAction(event.getToken(), new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("망쵸", "OUT"))))) - .doesNotThrowAnyException(); - } - - @DisplayName("행사에서 퇴장한 경우에 입장할 수 있다.") - @Test - void saveMemberActionTest1() { - Event event = eventRepository.save(Fixture.EVENT1); - MemberAction memberActionOne = Fixture.createMemberAction(event, 1L, "망쵸", IN); - memberActionRepository.save(memberActionOne); - - MemberAction memberActionTwo = Fixture.createMemberAction(event, 2L, "망쵸", OUT); - memberActionRepository.save(memberActionTwo); - - assertThatCode(() -> memberActionService.saveMemberAction(event.getToken(), new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("망쵸", "IN"))))) - .doesNotThrowAnyException(); - } - - @DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다.") - @Test - void saveMemberActionTest2() { - MemberActionsSaveAppRequest appRequest = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("TOKEN", "OUT"))); - - assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", appRequest)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("이벤트가 없으면 현재 참여 인원을 조회할 수 없다.") - @Test - void getCurrentMembers() { - assertThatThrownBy(() -> memberActionService.getCurrentMembers("token")) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("행사의 전체 참여자 중에서 특정 참여자의 맴버 액션을 전부 삭제한다.") - @Test - void deleteMember() { - Event event = Fixture.EVENT1; - eventRepository.save(event); - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "참여자", IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "토다리", IN); - MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "쿠키", IN); - MemberAction memberAction4 = Fixture.createMemberAction(event, 4L, "소하", IN); - MemberAction memberAction5 = Fixture.createMemberAction(event, 5L, "웨디", IN); - MemberAction memberAction6 = Fixture.createMemberAction(event, 6L, "참여자", OUT); - memberActionRepository.saveAll( - List.of(memberAction1, memberAction2, memberAction3, memberAction4, memberAction5, memberAction6)); - - Event event2 = Fixture.EVENT2; - eventRepository.save(event2); - MemberAction anotherMemberAction = Fixture.createMemberAction(event2, 1L, "참여자", IN); - memberActionRepository.save(anotherMemberAction); - - memberActionService.deleteMember(event.getToken(), "참여자"); - - List<MemberAction> memberActions = memberActionRepository.findAll(); - - assertThat(memberActions).hasSize(5) - .extracting("memberName", "status") - .containsExactly( - tuple("토다리", IN), - tuple("쿠키", IN), - tuple("소하", IN), - tuple("웨디", IN), - tuple("참여자", IN) - ); - } - - @DisplayName("이벤트에 속한 멤버을 삭제하면 전체 지출 내역 디테일이 초기화된다.") - @Test - void deleteMember1() { - Event event = Fixture.EVENT1; - eventRepository.save(event); - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "토다리", OUT); - MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "쿠키", IN); - MemberAction memberAction4 = Fixture.createMemberAction(event, 4L, "웨디", IN); - MemberAction memberAction5 = Fixture.createMemberAction(event, 5L, "감자", IN); - memberActionRepository.saveAll( - List.of(memberAction1, - memberAction2, - memberAction3, - memberAction4, - memberAction5 - ) - ); - BillAction billAction = Fixture.createBillAction(event, 6L, "뽕족", 100_000L); - billActionRepository.save(billAction); - BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "쿠키", 40_000L, true); - BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "웨디", 30_000L, false); - BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "감자", 30_000L, false); - billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3)); - - memberActionService.deleteMember(event.getToken(), "쿠키"); - - List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(billAction); - - assertThat(billActionDetails).hasSize(2) - .extracting("memberName", "price") - .containsExactlyInAnyOrder( - tuple("웨디", 50_000L), - tuple("감자", 50_000L) - ); - } - - @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") - @Test - void deleteMemberAction() { - Event event = Fixture.EVENT1; - eventRepository.save(event); - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "토다리", OUT); - MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "쿠키", IN); - MemberAction memberAction4 = Fixture.createMemberAction(event, 4L, "웨디", IN); - MemberAction memberAction5 = Fixture.createMemberAction(event, 5L, "토다리", IN); - MemberAction memberAction6 = Fixture.createMemberAction(event, 6L, "토다리", OUT); - MemberAction memberAction7 = Fixture.createMemberAction(event, 7L, "쿠키", OUT); - memberActionRepository.saveAll( - List.of(memberAction1, - memberAction2, - memberAction3, - memberAction4, - memberAction5, - memberAction6, - memberAction7) - ); - - memberActionService.deleteMemberAction(event.getToken(), memberAction2.getId()); - List<MemberAction> memberActions = memberActionRepository.findAll(); - - assertThat(memberActions).hasSize(4) - .extracting("id", "memberName", "status") - .containsExactly( - tuple(memberAction1.getId(), "토다리", IN), - tuple(memberAction3.getId(), "쿠키", IN), - tuple(memberAction4.getId(), "웨디", IN), - tuple(memberAction7.getId(), "쿠키", OUT) - ); - } - - @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후 지출 내역 디테일이 초기화된다.") - @Test - void deleteMemberAction1() { - Event event = Fixture.EVENT1; - eventRepository.save(event); - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "토다리", OUT); - MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "쿠키", IN); - MemberAction memberAction4 = Fixture.createMemberAction(event, 4L, "웨디", IN); - MemberAction memberAction5 = Fixture.createMemberAction(event, 5L, "감자", IN); - memberActionRepository.saveAll( - List.of(memberAction1, - memberAction2, - memberAction3, - memberAction4, - memberAction5 - ) - ); - BillAction billAction = Fixture.createBillAction(event, 6L, "뽕족", 100_000L); - billActionRepository.save(billAction); - BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "쿠키", 40_000L, true); - BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "웨디", 30_000L, false); - BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "감자", 30_000L, false); - billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3)); - - memberActionService.deleteMemberAction(event.getToken(), memberAction2.getId()); - List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(billAction); - - assertThat(billActionDetails).hasSize(4) - .extracting("memberName", "price") - .containsExactlyInAnyOrder( - tuple("토다리", 25_000L), - tuple("쿠키", 25_000L), - tuple("웨디", 25_000L), - tuple("감자", 25_000L) - ); - } -} diff --git a/server/src/test/java/server/haengdong/application/MemberServiceTest.java b/server/src/test/java/server/haengdong/application/MemberServiceTest.java new file mode 100644 index 000000000..88709eb29 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/MemberServiceTest.java @@ -0,0 +1,364 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static server.haengdong.support.fixture.Fixture.BILL1; +import static server.haengdong.support.fixture.Fixture.EVENT1; +import static server.haengdong.support.fixture.Fixture.EVENT2; +import static server.haengdong.support.fixture.Fixture.MEMBER1; +import static server.haengdong.support.fixture.Fixture.MEMBER2; +import static server.haengdong.support.fixture.Fixture.MEMBER3; + +import java.util.List; +import org.assertj.core.groups.Tuple; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import server.haengdong.application.request.MemberSaveAppRequest; +import server.haengdong.application.request.MemberUpdateAppRequest; +import server.haengdong.application.request.MembersSaveAppRequest; +import server.haengdong.application.request.MembersUpdateAppRequest; +import server.haengdong.application.response.MemberAppResponse; +import server.haengdong.application.response.MemberDepositAppResponse; +import server.haengdong.application.response.MemberSaveAppResponse; +import server.haengdong.application.response.MembersDepositAppResponse; +import server.haengdong.application.response.MembersSaveAppResponse; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.bill.BillDetail; +import server.haengdong.domain.bill.BillDetailRepository; +import server.haengdong.domain.bill.BillRepository; +import server.haengdong.domain.member.Member; +import server.haengdong.domain.member.MemberRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongException; + +class MemberServiceTest extends ServiceTestSupport { + + @Autowired + private MemberService memberService; + + @Autowired + private MemberRepository memberRepository; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillRepository billRepository; + + @Autowired + private BillDetailRepository billDetailRepository; + + @DisplayName("행사에 참여자를 추가한다.") + @Test + void saveMembersTest() { + Event event = EVENT1; + String memberName1 = "웨디"; + String memberName2 = "쿠키"; + Member member1 = new Member(event, memberName1); + Member member2 = new Member(event, memberName2); + eventRepository.save(event); + MembersSaveAppRequest request = new MembersSaveAppRequest( + List.of( + new MemberSaveAppRequest(member1.getName()), + new MemberSaveAppRequest(member2.getName()) + ) + ); + + MembersSaveAppResponse response = memberService.saveMembers(event.getToken(), request); + + List<Member> savedMembers = memberRepository.findAll(); + assertAll( + () -> assertThat(savedMembers) + .extracting(Member::getName) + .containsExactlyInAnyOrder(memberName1, memberName2), + () -> assertThat(response.members()) + .extracting(MemberSaveAppResponse::id, MemberSaveAppResponse::name) + .containsExactlyInAnyOrder( + Tuple.tuple(response.members().get(0).id(), memberName1), + Tuple.tuple(response.members().get(1).id(), memberName2) + ) + ); + } + + @DisplayName("행사에 존재하는 참여자를 추가하는 경우 예외가 발생한다.") + @Test + void saveMembersTest1() { + Event event = EVENT1; + Member member1 = MEMBER1; + Member member2 = MEMBER2; + eventRepository.save(event); + memberRepository.save(member1); + MembersSaveAppRequest request = new MembersSaveAppRequest( + List.of( + new MemberSaveAppRequest(member1.getName()), + new MemberSaveAppRequest(member2.getName()) + ) + ); + + assertThatThrownBy(() -> memberService.saveMembers(event.getToken(), request)) + .isInstanceOf(HaengdongException.class) + .hasMessage("현재 참여하고 있는 인원이 존재합니다."); + } + + @DisplayName("중복된 이름이 존재하는 경우 예외가 발생한다.") + @Test + void saveMembersTest2() { + Event event = EVENT1; + eventRepository.save(event); + MembersSaveAppRequest request = new MembersSaveAppRequest( + List.of( + new MemberSaveAppRequest("토다리"), + new MemberSaveAppRequest("토다리") + ) + ); + + assertThatThrownBy(() -> memberService.saveMembers(event.getToken(), request)) + .isInstanceOf(HaengdongException.class) + .hasMessageContaining("중복된 이름이 존재합니다. 입력된 이름: [토다리, 토다리]"); + } + + @DisplayName("행사 참여 인원을 삭제한다.") + @Test + void deleteMemberTest() { + Event event = EVENT1; + Member member = MEMBER1; + eventRepository.save(event); + memberRepository.save(member); + + memberService.deleteMember(event.getToken(), member.getId()); + + assertThat(memberRepository.findById(member.getId())).isEmpty(); + } + + @DisplayName("다른 이벤트의 참여 인원을 삭제하는 경우 예외가 발생한다.") + @Test + void deleteMemberTest1() { + Event event1 = EVENT1; + Event event2 = EVENT2; + Member member = new Member(EVENT2, "감자"); + eventRepository.saveAll(List.of(event1, event2)); + memberRepository.save(member); + + assertThatThrownBy(() -> memberService.deleteMember(event1.getToken(), member.getId())) + .isInstanceOf(HaengdongException.class); + + assertThat(memberRepository.findById(member.getId())).isNotEmpty(); + } + + @DisplayName("행사 참여 인원을 삭제하는 경우 해당 참여자가 포함된 Bill이 초기화된다.") + @Test + void deleteMemberTest2() { + Event event1 = EVENT1; + Member member1 = MEMBER1; + Member member2 = MEMBER2; + List<Member> members = List.of(member1, member2); + Bill bill = Bill.create(event1, "title", 10000L, members); + eventRepository.save(event1); + memberRepository.saveAll(members); + + BillDetail billDetail1 = getDetailByMember(bill, member1); + BillDetail billDetail2 = getDetailByMember(bill, member2); + billDetail1.updatePrice(8000L); + billDetail1.updateIsFixed(false); + billDetail2.updatePrice(2000L); + billDetail2.updateIsFixed(true); + billRepository.save(bill); + + memberService.deleteMember(event1.getToken(), member1.getId()); + + assertAll( + () -> assertThat(memberRepository.findById(member1.getId())).isEmpty(), + () -> assertThat(billDetailRepository.findById(billDetail1.getId())).isEmpty(), + () -> { + BillDetail foundDetail = billDetailRepository.findById(billDetail2.getId()).orElseThrow(); + assertThat(foundDetail.getPrice()).isEqualTo(10000L); + assertThat(foundDetail.isFixed()).isEqualTo(false); + } + ); + } + + private BillDetail getDetailByMember(Bill bill, Member member) { + return bill.getBillDetails() + .stream() + .filter(billDetail -> billDetail.isMember(member)) + .findFirst() + .orElseThrow(); + } + + @DisplayName("멤버 정보를 수정한다.") + @Test + void updateMembersTest() { + Event event = EVENT1; + Member member = MEMBER1; + eventRepository.save(event); + memberRepository.save(member); + MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( + List.of( + new MemberUpdateAppRequest(member.getId(), "수정된이름", true) + ) + ); + + memberService.updateMembers(event.getToken(), membersUpdateAppRequest); + + Member updatedMember = memberRepository.findById(member.getId()).orElseThrow(); + assertAll( + () -> assertThat(updatedMember.getName()).isEqualTo("수정된이름"), + () -> assertTrue(updatedMember.isDeposited()) + ); + } + + @DisplayName("수정할 멤버 id가 중복된 경우 예외가 발생한다.") + @Test + void updateMembersTest2() { + Event event = EVENT1; + Member member = MEMBER1; + eventRepository.save(event); + memberRepository.save(member); + MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( + List.of( + new MemberUpdateAppRequest(member.getId(), "수정", true), + new MemberUpdateAppRequest(member.getId(), "수정수정", false) + ) + ); + + assertThatThrownBy(() -> memberService.updateMembers(event.getToken(), membersUpdateAppRequest)) + .isInstanceOf(HaengdongException.class) + .hasMessage("중복된 참여 인원 이름 변경 요청이 존재합니다."); + } + + @DisplayName("수정할 멤버 이름이 중복된 경우 예외가 발생한다.") + @Test + void updateMembersTest3() { + Event event = EVENT1; + Member member1 = MEMBER1; + Member member2 = MEMBER2; + eventRepository.save(event); + memberRepository.saveAll(List.of(member1, member2)); + MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( + List.of( + new MemberUpdateAppRequest(member1.getId(), "수정", true), + new MemberUpdateAppRequest(member2.getId(), "수정", false) + ) + ); + + assertThatThrownBy(() -> memberService.updateMembers(event.getToken(), membersUpdateAppRequest)) + .isInstanceOf(HaengdongException.class) + .hasMessage("중복된 참여 인원 이름 변경 요청이 존재합니다."); + } + + @DisplayName("수정할 멤버가 행사에 존재하지 않는 경우 예외가 발생한다.") + @Test + void updateMembersTest4() { + Event event1 = EVENT1; + Event event2 = EVENT2; + Member member = new Member(event2, "이상"); + eventRepository.saveAll(List.of(event1, event2)); + memberRepository.save(member); + MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( + List.of( + new MemberUpdateAppRequest(member.getId(), "수정", true) + ) + ); + + assertThatThrownBy(() -> memberService.updateMembers(event1.getToken(), membersUpdateAppRequest)) + .isInstanceOf(HaengdongException.class) + .hasMessage("존재하지 않는 참여자입니다."); + } + + @DisplayName("수정하려는 행사 참여 인원 이름이 이미 존재하는 경우 예외가 발생한다.") + @Test + void updateMembersTest5() { + Event event1 = EVENT1; + Member member1 = MEMBER1; + Member member2 = MEMBER2; + eventRepository.save(event1); + memberRepository.saveAll(List.of(member1, member2)); + MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( + List.of( + new MemberUpdateAppRequest(member1.getId(), member2.getName(), true) + ) + ); + + assertThatThrownBy(() -> memberService.updateMembers(event1.getToken(), membersUpdateAppRequest)) + .isInstanceOf(HaengdongException.class) + .hasMessage("중복된 행사 참여 인원 이름이 존재합니다."); + } + + @DisplayName("참여자 간 서로의 이름으로 수정하려는 경우 예외가 발생한다.") + @Test + void updateMembersTest6() { + Event event = EVENT1; + Member member1 = MEMBER1; + Member member2 = MEMBER2; + eventRepository.save(event); + memberRepository.saveAll(List.of(member1, member2)); + MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( + List.of( + new MemberUpdateAppRequest(member1.getId(), member2.getName(), true), + new MemberUpdateAppRequest(member2.getId(), member1.getName(), false) + ) + ); + + assertThatThrownBy(() -> memberService.updateMembers(event.getToken(), membersUpdateAppRequest)) + .isInstanceOf(HaengdongException.class) + .hasMessage("중복된 행사 참여 인원 이름이 존재합니다."); + } + + @DisplayName("행사에 참여한 전체 인원을 조회한다.") + @Test + void findAllMembersTest() { + Event event = EVENT1; + Bill bill = BILL1; + Member member1 = MEMBER1; + Member member2 = MEMBER2; + Member member3 = MEMBER3; + eventRepository.save(event); + memberRepository.saveAll(List.of(member1, member2, member3)); + billRepository.save(bill); + + MembersDepositAppResponse membersDepositAppResponse = memberService.findAllMembers(event.getToken()); + + assertThat(membersDepositAppResponse.members()).hasSize(3) + .extracting(MemberDepositAppResponse::name, MemberDepositAppResponse::isDeposited) + .containsExactlyInAnyOrder( + tuple(member1.getName(), member1.isDeposited()), + tuple(member2.getName(), member2.isDeposited()), + tuple(member3.getName(), member3.isDeposited()) + ); + } + + @DisplayName("행사에 현재 참여 중인 인원을 조회한다.") + @Test + void getCurrentMembersTest() { + Event event = EVENT1; + Member member1 = MEMBER1; + Member member2 = MEMBER2; + Member member3 = MEMBER3; + Bill bill = Bill.create(event, "title", 100000L, List.of(member1, member2, member3)); + eventRepository.save(event); + memberRepository.saveAll(List.of(member1, member2, member3)); + billRepository.save(bill); + + List<MemberAppResponse> currentMembers = memberService.getCurrentMembers(event.getToken()); + + assertThat(currentMembers).hasSize(3) + .extracting(MemberAppResponse::id, MemberAppResponse::name) + .containsExactlyInAnyOrder( + tuple(member1.getId(), member1.getName()), + tuple(member2.getId(), member2.getName()), + tuple(member3.getId(), member3.getName()) + ); + } + + @DisplayName("행사가 없으면 현재 참여 인원을 조회할 수 없다.") + @Test + void getCurrentMembersTest1() { + assertThatThrownBy(() -> memberService.getCurrentMembers("token")) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/docs/AdminBillActionControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/AdminBillControllerDocsTest.java similarity index 60% rename from server/src/test/java/server/haengdong/docs/AdminBillActionControllerDocsTest.java rename to server/src/test/java/server/haengdong/docs/AdminBillControllerDocsTest.java index 705adaa5c..1c275801e 100644 --- a/server/src/test/java/server/haengdong/docs/AdminBillActionControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/AdminBillControllerDocsTest.java @@ -23,44 +23,39 @@ import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; import org.springframework.restdocs.payload.JsonFieldType; -import server.haengdong.application.BillActionDetailService; -import server.haengdong.application.BillActionService; -import server.haengdong.presentation.admin.AdminBillActionController; -import server.haengdong.presentation.request.BillActionDetailUpdateRequest; -import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; -import server.haengdong.presentation.request.BillActionSaveRequest; -import server.haengdong.presentation.request.BillActionUpdateRequest; -import server.haengdong.presentation.request.BillActionsSaveRequest; +import server.haengdong.application.BillService; +import server.haengdong.presentation.admin.AdminBillController; +import server.haengdong.presentation.request.BillDetailUpdateRequest; +import server.haengdong.presentation.request.BillDetailsUpdateRequest; +import server.haengdong.presentation.request.BillSaveRequest; +import server.haengdong.presentation.request.BillUpdateRequest; +import server.haengdong.support.fixture.Fixture; -class AdminBillActionControllerDocsTest extends RestDocsSupport { +class AdminBillControllerDocsTest extends RestDocsSupport { - private final BillActionService billActionService = mock(BillActionService.class); - private final BillActionDetailService billActionDetailService = mock(BillActionDetailService.class); + private final BillService billService = mock(BillService.class); @Override protected Object initController() { - return new AdminBillActionController(billActionService, billActionDetailService); + return new AdminBillController(billService); } @DisplayName("지출 내역을 생성한다.") @Test - void saveAllBillAction() throws Exception { - BillActionsSaveRequest request = new BillActionsSaveRequest( - List.of( - new BillActionSaveRequest("뽕족", 10_000L), - new BillActionSaveRequest("인생맥주", 10_000L) - ) - ); + void saveAllBill() throws Exception { + List<Long> members = List.of(1L, 2L); + BillSaveRequest request = new BillSaveRequest("뽕족", 10_000L, members); + String requestBody = objectMapper.writeValueAsString(request); String eventId = "쿠키토큰"; - mockMvc.perform(post("/api/admin/events/{eventId}/bill-actions", eventId) + mockMvc.perform(post("/api/admin/events/{eventId}/bills", eventId) .contentType(MediaType.APPLICATION_JSON) - .cookie(EVENT_COOKIE) - .content(requestBody)) + .content(requestBody) + .cookie(Fixture.EVENT_COOKIE)) .andDo(print()) .andExpect(status().isOk()) - .andDo(document("createBillActions", + .andDo(document("createBills", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), pathParameters( @@ -70,81 +65,81 @@ void saveAllBillAction() throws Exception { cookieWithName("eventToken").description("행사 관리자 토큰") ), requestFields( - fieldWithPath("actions").description("생성할 지출 액션 목록"), - fieldWithPath("actions[0].title").description("생성할 지출 액션의 제목"), - fieldWithPath("actions[0].price").description("생성할 지출 액션의 금액") + fieldWithPath("title").description("생성할 지출 제목"), + fieldWithPath("price").description("생성할 지출 금액"), + fieldWithPath("memberIds").description("생성할 지출의 참여인원 ID 리스트") ) )); } - @DisplayName("지출 액션을 수정한다.") + @DisplayName("지출을 수정한다.") @Test - void updateBillAction() throws Exception { - BillActionUpdateRequest request = new BillActionUpdateRequest("뽕족", 10_000L); + void updateBill() throws Exception { + BillUpdateRequest request = new BillUpdateRequest("뽕족", 10_000L); String requestBody = objectMapper.writeValueAsString(request); String eventId = "웨디토큰"; - mockMvc.perform(put("/api/admin/events/{eventId}/bill-actions/{actionId}", eventId, 1L) - .cookie(EVENT_COOKIE) + mockMvc.perform(put("/api/admin/events/{eventId}/bills/{billId}", eventId, 1L) .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + .content(requestBody) + .cookie(EVENT_COOKIE)) .andDo(print()) .andExpect(status().isOk()) - .andDo(document("updateBillAction", + .andDo(document("updateBill", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), pathParameters( parameterWithName("eventId").description("행사 ID"), - parameterWithName("actionId").description("지출 액션 ID") + parameterWithName("billId").description("지출 ID") ), requestCookies( cookieWithName("eventToken").description("행사 관리자 토큰") ), requestFields( - fieldWithPath("title").description("수정할 지출 액션의 제목"), - fieldWithPath("price").description("수정할 지출 액션의 금액") + fieldWithPath("title").description("수정할 지출 제목"), + fieldWithPath("price").description("수정할 지출 금액") ) )); } @DisplayName("참여자별 지출 금액을 수정한다.") @Test - void updateBillActionDetailsTest() throws Exception { - List<BillActionDetailUpdateRequest> billActionDetailUpdateRequests = List.of( - new BillActionDetailUpdateRequest("소하", 10000L, true), - new BillActionDetailUpdateRequest("웨디", 20000L, true) + void updateBillDetailsTest() throws Exception { + List<BillDetailUpdateRequest> billDetailUpdateRequests = List.of( + new BillDetailUpdateRequest(1L, 10000L, true), + new BillDetailUpdateRequest(2L, 20000L, true) ); - BillActionDetailsUpdateRequest request = new BillActionDetailsUpdateRequest( - billActionDetailUpdateRequests); + BillDetailsUpdateRequest request = new BillDetailsUpdateRequest( + billDetailUpdateRequests); String json = objectMapper.writeValueAsString(request); - mockMvc.perform(put("/api/admin/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L) + mockMvc.perform(put("/api/admin/events/{eventId}/bills/{billId}/details", "TOKEN", 1L) .cookie(EVENT_COOKIE) .contentType(MediaType.APPLICATION_JSON) .content(json)) .andDo(print()) .andExpect(status().isOk()) .andDo( - document("updateBillActionDetailsTest", + document("updateBillDetails", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), pathParameters( parameterWithName("eventId").description("행사 ID"), - parameterWithName("actionId").description("액션 ID") + parameterWithName("billId").description("지출 ID") ), requestCookies( cookieWithName("eventToken").description("행사 관리자 토큰") ), requestFields( - fieldWithPath("members").type(JsonFieldType.ARRAY) + fieldWithPath("billDetails").type(JsonFieldType.ARRAY) .description("전체 정산 수정 요청 목록"), - fieldWithPath("members[0].name").type(JsonFieldType.STRING) + fieldWithPath("billDetails[0].id").type(JsonFieldType.NUMBER) .description("참여자 이름"), - fieldWithPath("members[0].price").type(JsonFieldType.NUMBER) + fieldWithPath("billDetails[0].price").type(JsonFieldType.NUMBER) .description("참여자 정산 금액"), - fieldWithPath("members[0].isFixed").type(JsonFieldType.BOOLEAN) + fieldWithPath("billDetails[0].isFixed").type(JsonFieldType.BOOLEAN) .description("참여자 정산 금액 수정 여부") ) ) @@ -153,20 +148,20 @@ void updateBillActionDetailsTest() throws Exception { @DisplayName("지출 내역을 삭제한다.") @Test - void deleteBillAction() throws Exception { + void deleteBill() throws Exception { String eventId = "토다리토큰"; - mockMvc.perform(delete("/api/admin/events/{eventId}/bill-actions/{actionId}", eventId, 1) + mockMvc.perform(delete("/api/admin/events/{eventId}/bills/{billId}", eventId, 1) .cookie(EVENT_COOKIE) ) .andDo(print()) .andExpect(status().isOk()) - .andDo(document("deleteBillAction", + .andDo(document("deleteBill", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), pathParameters( parameterWithName("eventId").description("행사 ID"), - parameterWithName("actionId").description("지출 액션 ID") + parameterWithName("billId").description("지출 ID") ), requestCookies( cookieWithName("eventToken").description("행사 관리자 토큰") diff --git a/server/src/test/java/server/haengdong/docs/AdminEventControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/AdminEventControllerDocsTest.java index 956035e92..22c028169 100644 --- a/server/src/test/java/server/haengdong/docs/AdminEventControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/AdminEventControllerDocsTest.java @@ -4,8 +4,8 @@ import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.patch; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; @@ -17,17 +17,15 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; -import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; import org.springframework.restdocs.payload.JsonFieldType; import server.haengdong.application.EventService; import server.haengdong.presentation.admin.AdminEventController; -import server.haengdong.presentation.request.MemberNameUpdateRequest; -import server.haengdong.presentation.request.MemberNamesUpdateRequest; +import server.haengdong.presentation.request.EventUpdateRequest; -public class AdminEventControllerDocsTest extends RestDocsSupport { +class AdminEventControllerDocsTest extends RestDocsSupport { private final EventService eventService = mock(EventService.class); @@ -59,40 +57,38 @@ void authenticateTest() throws Exception { ); } - @DisplayName("행사 참여 인원의 이름을 수정한다.") + @DisplayName("행사 정보를 업데이트한다.") @Test - void updateMember() throws Exception { + void updateEventTest() throws Exception { String token = "TOKEN"; - MemberNamesUpdateRequest memberNameUpdateRequest = new MemberNamesUpdateRequest(List.of( - new MemberNameUpdateRequest("토다링", "토쟁이"), - new MemberNameUpdateRequest("감자", "고구마") - )); + EventUpdateRequest eventUpdateRequest = new EventUpdateRequest("행동대장 비대위", "행대뱅크", "12345678"); - String requestBody = objectMapper.writeValueAsString(memberNameUpdateRequest); + String requestBody = objectMapper.writeValueAsString(eventUpdateRequest); - mockMvc.perform(put("/api/admin/events/{eventId}/members/nameChange", token) - .cookie(EVENT_COOKIE) - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + mockMvc.perform(patch("/api/admin/events/{eventId}", token) + .cookie(EVENT_COOKIE) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) .andDo(print()) .andExpect(status().isOk()) .andDo( - document("updateEventMemberName", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") - ), - requestFields( - fieldWithPath("members").type(JsonFieldType.ARRAY).description("수정할 참여자 목록"), - fieldWithPath("members[].before").type(JsonFieldType.STRING) - .description("수정 전 참여자 이름"), - fieldWithPath("members[].after").type(JsonFieldType.STRING) - .description("수정 후 참여자 이름") - ) + document("updateEvent", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), + requestFields( + fieldWithPath("eventName").type(JsonFieldType.STRING) + .description("수정할 이벤트 이름").optional(), + fieldWithPath("bankName").type(JsonFieldType.STRING) + .description("은행 이름").optional(), + fieldWithPath("accountNumber").type(JsonFieldType.STRING) + .description("계좌 번호").optional() + ) ) ); } diff --git a/server/src/test/java/server/haengdong/docs/AdminMemberActionControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/AdminMemberActionControllerDocsTest.java deleted file mode 100644 index f8a4f7dbd..000000000 --- a/server/src/test/java/server/haengdong/docs/AdminMemberActionControllerDocsTest.java +++ /dev/null @@ -1,121 +0,0 @@ -package server.haengdong.docs; - -import static org.mockito.Mockito.mock; -import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; -import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; -import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; -import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; -import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; -import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.http.MediaType; -import org.springframework.restdocs.payload.JsonFieldType; -import server.haengdong.application.MemberActionService; -import server.haengdong.presentation.admin.AdminMemberActionController; -import server.haengdong.presentation.request.MemberActionsSaveRequest; - -public class AdminMemberActionControllerDocsTest extends RestDocsSupport { - - private final MemberActionService memberActionService = mock(MemberActionService.class); - - @Override - protected Object initController() { - return new AdminMemberActionController(memberActionService); - } - - @DisplayName("참여자 행동을 추가한다.") - @Test - void saveMemberActionTest() throws Exception { - MemberActionsSaveRequest memberActionsSaveRequest = new MemberActionsSaveRequest( - List.of("웨디", "소하", "토다리", "쿠키"), "IN"); - - String requestBody = objectMapper.writeValueAsString(memberActionsSaveRequest); - - mockMvc.perform(post("/api/admin/events/{eventId}/member-actions", "망쵸토큰") - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody) - .cookie(EVENT_COOKIE)) - .andDo(print()) - .andExpect(status().isOk()) - .andDo( - document("createMemberAction", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - requestCookies( - cookieWithName("eventToken").description("토큰 토큰") - ), - requestFields( - fieldWithPath("members").type(JsonFieldType.ARRAY) - .description("액션 대상 참여자 목록"), - fieldWithPath("status").type(JsonFieldType.STRING) - .description("참여자 액션 상태 [IN(늦참), OUT(탈주)]") - ) - ) - ); - } - - @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") - @Test - void deleteMemberAction() throws Exception { - String eventId = "망쵸토큰"; - Long actionId = 2L; - - mockMvc.perform(delete("/api/admin/events/{eventId}/member-actions/{actionId}", eventId, actionId) - .cookie(EVENT_COOKIE)) - .andDo(print()) - .andExpect(status().isOk()) - .andDo( - document("deleteMemberAction", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID"), - parameterWithName("actionId").description("액션 ID") - ), - requestCookies( - cookieWithName("eventToken").description("행사 관리자용 토큰") - ) - ) - ); - } - - @DisplayName("행사의 전체 참여자 중에서 특정 참여자의 맴버 액션을 전부 삭제한다.") - @Test - void deleteMember() throws Exception { - String eventId = "망쵸토큰"; - String memberName = "행동대장"; - - mockMvc.perform(delete("/api/admin/events/{eventId}/members/{memberName}", eventId, memberName) - .cookie(EVENT_COOKIE)) - .andDo(print()) - .andExpect(status().isOk()) - .andDo( - document("deleteAllMemberActionByName", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID"), - parameterWithName("memberName").description("행사 참여자 이름") - ), - requestCookies( - cookieWithName("eventToken").description("행사 관리자용 토큰") - ) - ) - ); - } -} diff --git a/server/src/test/java/server/haengdong/docs/AdminMemberControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/AdminMemberControllerDocsTest.java new file mode 100644 index 000000000..9d70673f9 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/AdminMemberControllerDocsTest.java @@ -0,0 +1,173 @@ +package server.haengdong.docs; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; +import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import server.haengdong.application.MemberService; +import server.haengdong.application.response.MemberSaveAppResponse; +import server.haengdong.application.response.MembersSaveAppResponse; +import server.haengdong.presentation.admin.AdminMemberController; +import server.haengdong.presentation.request.MemberSaveRequest; +import server.haengdong.presentation.request.MemberUpdateRequest; +import server.haengdong.presentation.request.MembersSaveRequest; +import server.haengdong.presentation.request.MembersUpdateRequest; + +class AdminMemberControllerDocsTest extends RestDocsSupport { + + private final MemberService memberService = mock(MemberService.class); + + @Override + protected Object initController() { + return new AdminMemberController(memberService); + } + + @DisplayName("행사 참여자를 추가한다.") + @Test + void saveMemberTest() throws Exception { + String eventToken = "망쵸토큰"; + MembersSaveRequest membersSaveRequest = new MembersSaveRequest( + List.of( + new MemberSaveRequest("웨디"), + new MemberSaveRequest("소하") + ) + ); + String requestBody = objectMapper.writeValueAsString(membersSaveRequest); + MembersSaveAppResponse appResponse = new MembersSaveAppResponse( + List.of( + new MemberSaveAppResponse(1L, "웨디"), + new MemberSaveAppResponse(2L, "소하") + ) + ); + given(memberService.saveMembers(eventToken, membersSaveRequest.toAppRequest())) + .willReturn(appResponse); + + mockMvc.perform(post("/api/admin/events/{eventId}/members", "망쵸토큰") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.members[0].id").value(equalTo(1))) + .andExpect(MockMvcResultMatchers.jsonPath("$.members[0].name").value(equalTo("웨디"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.members[1].id").value(equalTo(2))) + .andExpect(MockMvcResultMatchers.jsonPath("$.members[1].name").value(equalTo("소하"))) + .andDo( + document("saveMembers", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("토큰 토큰") + ), + requestFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("행사에 추가할 참여자 목록"), + fieldWithPath("members[].name").type(JsonFieldType.STRING) + .description("참여자 이름") + ), + responseFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("행사에 추가된 참여자 목록"), + fieldWithPath("members[].id").type(JsonFieldType.NUMBER) + .description("참여자 ID"), + fieldWithPath("members[].name").type(JsonFieldType.STRING) + .description("참여자 이름") + ) + ) + ); + } + + @DisplayName("행사 참여 인원을 삭제한다.") + @Test + void deleteMember() throws Exception { + String eventId = "망쵸토큰"; + Long memberId = 1L; + + mockMvc.perform(delete("/api/admin/events/{eventId}/members/{memberId}", eventId, memberId) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("deleteMember", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("memberId").description("삭제할 참여자 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 토큰") + ) + ) + ); + } + + @DisplayName("행사 참여 인원 정보를 수정한다.") + @Test + void updateMembers() throws Exception { + String eventId = "망쵸토큰"; + MembersUpdateRequest membersUpdateRequest = new MembersUpdateRequest( + List.of( + new MemberUpdateRequest(1L, "토다리", true), + new MemberUpdateRequest(2L, "쿠키", false) + ) + ); + String requestBody = objectMapper.writeValueAsString(membersUpdateRequest); + + mockMvc.perform(put("/api/admin/events/{eventId}/members", eventId) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + .cookie(EVENT_COOKIE) + ) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("updateMembers", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 토큰") + ), + requestFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("수정할 참여자 목록"), + fieldWithPath("members[].id").type(JsonFieldType.NUMBER) + .description("참여자 ID"), + fieldWithPath("members[].name").type(JsonFieldType.STRING) + .description("참여자 이름"), + fieldWithPath("members[].isDeposited").type(JsonFieldType.BOOLEAN) + .description("참여자 입금 여부") + ) + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java deleted file mode 100644 index d79bd2c02..000000000 --- a/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java +++ /dev/null @@ -1,79 +0,0 @@ -package server.haengdong.docs; - -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; -import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; -import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; -import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; -import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; -import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.restdocs.payload.JsonFieldType; -import server.haengdong.application.BillActionDetailService; -import server.haengdong.application.response.BillActionDetailAppResponse; -import server.haengdong.application.response.BillActionDetailsAppResponse; -import server.haengdong.presentation.BillActionDetailController; - -public class BillActionDetailControllerDocsTest extends RestDocsSupport { - - private final BillActionDetailService billActionDetailService = mock(BillActionDetailService.class); - - @Override - protected Object initController() { - return new BillActionDetailController(billActionDetailService); - } - - @DisplayName("참여자별 지출 금액을 조회한다.") - @Test - void findBillActionDetailsTest() throws Exception { - BillActionDetailsAppResponse appResponse = new BillActionDetailsAppResponse( - List.of(new BillActionDetailAppResponse("토다리", 1000L, false))); - given(billActionDetailService.findBillActionDetails(anyString(), anyLong())) - .willReturn(appResponse); - - mockMvc.perform(get("/api/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L) - .cookie(EVENT_COOKIE)) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.members").isArray()) - .andExpect(jsonPath("$.members[0].name").value("토다리")) - .andExpect(jsonPath("$.members[0].price").value(1000L)) - .andExpect(jsonPath("$.members[0].isFixed").value(false)) - .andDo( - document("findBillActionDetailsTest", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID"), - parameterWithName("actionId").description("액션 ID") - ), requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") - ), responseFields( - fieldWithPath("members").type(JsonFieldType.ARRAY) - .description("전체 정산 수정 요청 목록"), - fieldWithPath("members[0].name").type(JsonFieldType.STRING) - .description("참여자 이름"), - fieldWithPath("members[0].price").type(JsonFieldType.NUMBER) - .description("참여자 정산 금액"), - fieldWithPath("members[0].isFixed").type(JsonFieldType.BOOLEAN) - .description("참여자 정산 금액 수정 여부") - ) - ) - ); - } -} diff --git a/server/src/test/java/server/haengdong/docs/BillControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/BillControllerDocsTest.java new file mode 100644 index 000000000..f960d6195 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/BillControllerDocsTest.java @@ -0,0 +1,119 @@ +package server.haengdong.docs; + +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.application.BillService; +import server.haengdong.application.response.BillAppResponse; +import server.haengdong.application.response.BillDetailAppResponse; +import server.haengdong.application.response.BillDetailsAppResponse; +import server.haengdong.application.response.MemberAppResponse; +import server.haengdong.application.response.StepAppResponse; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.member.Member; +import server.haengdong.presentation.BillController; +import server.haengdong.support.fixture.Fixture; + +class BillControllerDocsTest extends RestDocsSupport { + + private final BillService billService = mock(BillService.class); + + @Override + protected Object initController() { + return new BillController(billService); + } + + @DisplayName("전체 지출 내역을 조회한다.") + @Test + void findBills() throws Exception { + Bill bill = Fixture.BILL1; + List<BillAppResponse> bills = List.of(BillAppResponse.of(bill)); + + Member member = Fixture.MEMBER1; + List<MemberAppResponse> members = List.of(MemberAppResponse.of(member)); + + StepAppResponse stepAppResponse = new StepAppResponse(bills, members); + given(billService.findSteps(anyString())).willReturn(List.of(stepAppResponse)); + + mockMvc.perform(get("/api/events/{eventId}/bills", "token")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.steps").isArray()) + .andExpect(jsonPath("$.steps[0].bills").isArray()) + .andExpect(jsonPath("$.steps[0].bills[0].id").value(bill.getId())) + .andExpect(jsonPath("$.steps[0].bills[0].title").value(bill.getTitle())) + .andExpect(jsonPath("$.steps[0].bills[0].price").value(bill.getPrice())) + .andExpect(jsonPath("$.steps[0].bills[0].isFixed").value(bill.isFixed())) + .andExpect(jsonPath("$.steps[0].members").isArray()) + .andExpect(jsonPath("$.steps[0].members[0].id").value(member.getId())) + .andExpect(jsonPath("$.steps[0].members[0].name").value(member.getName())) + .andDo(document("findBills", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("steps").description("지출 차수 목록"), + fieldWithPath("steps[].bills").description("해당 차수의 지출 내역"), + fieldWithPath("steps[].bills[].id").description("지출 ID"), + fieldWithPath("steps[].bills[].title").description("지출 이름"), + fieldWithPath("steps[].bills[].price").description("지출 금액"), + fieldWithPath("steps[].bills[].isFixed").description("지출 수정 여부"), + fieldWithPath("steps[].members").description("해당 차수의 참여자 목록"), + fieldWithPath("steps[].members[].id").description("참여자 ID"), + fieldWithPath("steps[].members[].name").description("참여자 이름") + ) + ) + ); + } + + + @DisplayName("참여자별 지출 금액을 조회한다.") + @Test + void findBillActionDetails() throws Exception { + BillDetailsAppResponse appResponse = new BillDetailsAppResponse( + List.of(new BillDetailAppResponse(1L, "토다리", 1000L, false))); + given(billService.findBillDetails(anyString(), anyLong())).willReturn(appResponse); + + mockMvc.perform(get("/api/events/{eventId}/bills/{billId}/details", "TOKEN", 1L)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").isArray()) + .andExpect(jsonPath("$.members[0].id").value(1L)) + .andExpect(jsonPath("$.members[0].memberName").value("토다리")) + .andExpect(jsonPath("$.members[0].price").value(1000L)) + .andExpect(jsonPath("$.members[0].isFixed").value(false)) + .andDo(document("findBillDetails", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("billId").description("지출 ID") + ), responseFields( + fieldWithPath("members").description("참여자 목록"), + fieldWithPath("members[].id").description("참여자 ID"), + fieldWithPath("members[].memberName").description("참여자 이름"), + fieldWithPath("members[].price").description("참여자별 지출 금액"), + fieldWithPath("members[].isFixed").description("지출 수정 여부") + ) + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java index 6950f3d23..36a752953 100644 --- a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java @@ -2,7 +2,6 @@ import static org.hamcrest.Matchers.equalTo; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; @@ -33,18 +32,15 @@ import server.haengdong.application.AuthService; import server.haengdong.application.EventService; import server.haengdong.application.request.EventAppRequest; -import server.haengdong.application.response.ActionAppResponse; -import server.haengdong.application.response.ActionAppResponse.ActionType; import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; import server.haengdong.application.response.MemberBillReportAppResponse; -import server.haengdong.application.response.MembersAppResponse; import server.haengdong.infrastructure.auth.CookieProperties; import server.haengdong.presentation.EventController; import server.haengdong.presentation.request.EventLoginRequest; import server.haengdong.presentation.request.EventSaveRequest; -public class EventControllerDocsTest extends RestDocsSupport { +class EventControllerDocsTest extends RestDocsSupport { private final EventService eventService = mock(EventService.class); private final AuthService authService = mock(AuthService.class); @@ -61,7 +57,7 @@ protected Object initController() { @Test void findEventTest() throws Exception { String eventId = "망쵸토큰"; - EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식"); + EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식", "토스 12312455"); given(eventService.findEvent(eventId)).willReturn(eventDetailAppResponse); mockMvc.perform(get("/api/events/{eventId}", eventId)) @@ -76,170 +72,8 @@ void findEventTest() throws Exception { parameterWithName("eventId").description("행사 ID") ), responseFields( - fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름") - ) - ) - ); - } - - @DisplayName("행사에 참여한 전체 인원을 중복 없이 조회한다.") - @Test - void findAllMembersTest() throws Exception { - MembersAppResponse memberAppResponse = new MembersAppResponse(List.of("토다리", "쿠키")); - given(eventService.findAllMembers(anyString())).willReturn(memberAppResponse); - - mockMvc.perform(get("/api/events/{eventId}/members", "TOKEN")) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.memberNames").isArray()) - .andExpect(jsonPath("$.memberNames[0]").value("토다리")) - .andExpect(jsonPath("$.memberNames[1]").value("쿠키")) - .andDo( - document("findAllEventMember", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - responseFields( - fieldWithPath("memberNames").type(JsonFieldType.ARRAY) - .description("행사 참여자 목록") - ) - ) - ); - } - - @DisplayName("행사 전체 액션 이력 조회") - @Test - void findActions() throws Exception { - String token = "TOKEN"; - List<ActionAppResponse> actionAppResponses = List.of( - new ActionAppResponse(1L, "망쵸", null, 1L, ActionType.IN), - new ActionAppResponse(2L, "족발", 100L, 2L, ActionType.BILL), - new ActionAppResponse(3L, "인생네컷", 1000L, 3L, ActionType.BILL), - new ActionAppResponse(4L, "망쵸", null, 4L, ActionType.OUT) - ); - given(eventService.findActions(token)).willReturn(actionAppResponses); - - mockMvc.perform(get("/api/events/{eventId}/actions", token) - .accept(MediaType.APPLICATION_JSON)) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.steps[0].type").value(equalTo("IN"))) - .andExpect(jsonPath("$.steps[0].stepName").value(equalTo("0차"))) - .andExpect(jsonPath("$.steps[0].members[0]").value(equalTo("망쵸"))) - .andExpect(jsonPath("$.steps[0].actions[0].actionId").value(equalTo(1))) - .andExpect(jsonPath("$.steps[0].actions[0].name").value(equalTo("망쵸"))) - .andExpect(jsonPath("$.steps[0].actions[0].price").value(equalTo(null))) - .andExpect(jsonPath("$.steps[0].actions[0].sequence").value(equalTo(1))) - - .andExpect(jsonPath("$.steps[1].type").value(equalTo("BILL"))) - .andExpect(jsonPath("$.steps[1].stepName").value(equalTo("1차"))) - .andExpect(jsonPath("$.steps[1].members[0]").value(equalTo("망쵸"))) - .andExpect(jsonPath("$.steps[1].actions[0].actionId").value(equalTo(2))) - .andExpect(jsonPath("$.steps[1].actions[0].name").value(equalTo("족발"))) - .andExpect(jsonPath("$.steps[1].actions[0].price").value(equalTo(100))) - .andExpect(jsonPath("$.steps[1].actions[0].sequence").value(equalTo(2))) - - .andExpect(jsonPath("$.steps[1].actions[1].actionId").value(equalTo(3))) - .andExpect(jsonPath("$.steps[1].actions[1].name").value(equalTo("인생네컷"))) - .andExpect(jsonPath("$.steps[1].actions[1].price").value(equalTo(1000))) - .andExpect(jsonPath("$.steps[1].actions[1].sequence").value(equalTo(3))) - - .andExpect(jsonPath("$.steps[2].type").value(equalTo("OUT"))) - .andExpect(jsonPath("$.steps[2].stepName").value(equalTo("1차"))) - .andExpect(jsonPath("$.steps[2].actions[0].actionId").value(equalTo(4))) - .andExpect(jsonPath("$.steps[2].actions[0].name").value(equalTo("망쵸"))) - .andExpect(jsonPath("$.steps[2].actions[0].price").value(equalTo(null))) - .andExpect(jsonPath("$.steps[2].actions[0].sequence").value(equalTo(4))) - - .andDo( - document("findActions", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - responseFields( - fieldWithPath("steps[].stepName").type(JsonFieldType.STRING) - .description("스탭 이름"), - fieldWithPath("steps[].type").type(JsonFieldType.STRING) - .description("액션 유형 [BILL, IN, OUT]"), - fieldWithPath("steps[].members").type(JsonFieldType.ARRAY) - .description("해당 step에 참여한 참여자 목록"), - fieldWithPath("steps[].actions[].actionId").type(JsonFieldType.NUMBER) - .description("액션 ID"), - fieldWithPath("steps[].actions[].name").type(JsonFieldType.STRING) - .description("참여자 액션일 경우 참여자 이름, 지출 액션일 경우 지출 내역 이름"), - fieldWithPath("steps[].actions[].price").type(JsonFieldType.NUMBER).optional() - .description("참여자 액션일 경우 null, 지출 액션일 경우 지출 금액"), - fieldWithPath("steps[].actions[].sequence").type(JsonFieldType.NUMBER) - .description("액션 순서"), - fieldWithPath("steps[].actions[].isFixed").type(JsonFieldType.BOOLEAN) - .description("지출 내역의 멤버별 고정 지출 금액 생성 여부") - ) - ) - ); - } - - @DisplayName("행사 전체 액션 이력 조회 v2") - @Test - void findActions2() throws Exception { - String token = "TOKEN"; - List<ActionAppResponse> actionAppResponses = List.of( - new ActionAppResponse(1L, "망쵸", null, 1L, ActionType.IN), - new ActionAppResponse(2L, "족발", 100L, 2L, ActionType.BILL), - new ActionAppResponse(3L, "인생네컷", 1000L, 3L, ActionType.BILL), - new ActionAppResponse(4L, "망쵸", null, 4L, ActionType.OUT) - ); - given(eventService.findActions(token)).willReturn(actionAppResponses); - - mockMvc.perform(get("/api/events/{eventId}/actions/v2", token) - .accept(MediaType.APPLICATION_JSON)) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.actions[0].actionId").value(equalTo(1))) - .andExpect(jsonPath("$.actions[0].name").value(equalTo("망쵸"))) - .andExpect(jsonPath("$.actions[0].price").value(equalTo(null))) - .andExpect(jsonPath("$.actions[0].sequence").value(equalTo(1))) - .andExpect(jsonPath("$.actions[0].type").value(equalTo("IN"))) - - .andExpect(jsonPath("$.actions[1].actionId").value(equalTo(2))) - .andExpect(jsonPath("$.actions[1].name").value(equalTo("족발"))) - .andExpect(jsonPath("$.actions[1].price").value(equalTo(100))) - .andExpect(jsonPath("$.actions[1].sequence").value(equalTo(2))) - .andExpect(jsonPath("$.actions[1].type").value(equalTo("BILL"))) - - .andExpect(jsonPath("$.actions[2].actionId").value(equalTo(3))) - .andExpect(jsonPath("$.actions[2].name").value(equalTo("인생네컷"))) - .andExpect(jsonPath("$.actions[2].price").value(equalTo(1000))) - .andExpect(jsonPath("$.actions[2].sequence").value(equalTo(3))) - .andExpect(jsonPath("$.actions[2].type").value(equalTo("BILL"))) - - .andExpect(jsonPath("$.actions[3].actionId").value(equalTo(4))) - .andExpect(jsonPath("$.actions[3].name").value(equalTo("망쵸"))) - .andExpect(jsonPath("$.actions[3].price").value(equalTo(null))) - .andExpect(jsonPath("$.actions[3].sequence").value(equalTo(4))) - .andExpect(jsonPath("$.actions[3].type").value(equalTo("OUT"))) - - .andDo( - document("findActions", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - responseFields( - fieldWithPath("actions[].actionId").type(JsonFieldType.NUMBER) - .description("액션 ID"), - fieldWithPath("actions[].name").type(JsonFieldType.STRING) - .description("참여자 액션일 경우 참여자 이름, 지출 액션일 경우 지출 내역 이름"), - fieldWithPath("actions[].price").type(JsonFieldType.NUMBER).optional() - .description("참여자 액션일 경우 null, 지출 액션일 경우 지출 금액"), - fieldWithPath("actions[].sequence").type(JsonFieldType.NUMBER) - .description("액션 순서"), - fieldWithPath("actions[].type").type(JsonFieldType.STRING) - .description("액션 타입") + fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름"), + fieldWithPath("account").type(JsonFieldType.STRING).description("행사 계좌") ) ) ); @@ -249,7 +83,9 @@ void findActions2() throws Exception { @Test void getMemberBillReports() throws Exception { List<MemberBillReportAppResponse> memberBillReportAppResponses = List.of( - new MemberBillReportAppResponse("소하", 20_000L), new MemberBillReportAppResponse("토다리", 200_000L)); + new MemberBillReportAppResponse(1L, "소하", false, 20_000L), + new MemberBillReportAppResponse(2L, "토다리", false, 200_000L) + ); given(eventService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); @@ -257,9 +93,13 @@ void getMemberBillReports() throws Exception { .accept(MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].name").value(equalTo("소하"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].memberId").value(equalTo(1))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].memberName").value(equalTo("소하"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].isDeposited").value(equalTo(false))) .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].price").value(equalTo(20_000))) - .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].name").value(equalTo("토다리"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].memberId").value(equalTo(2))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].memberName").value(equalTo("토다리"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].isDeposited").value(equalTo(false))) .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].price").value(equalTo(200_000))) .andDo( document("getMemberBillReports", @@ -270,7 +110,11 @@ void getMemberBillReports() throws Exception { ), responseFields( fieldWithPath("reports").type(JsonFieldType.ARRAY).description("전체 정산 현황 목록"), - fieldWithPath("reports[0].name").type(JsonFieldType.STRING) + fieldWithPath("reports[0].memberId").type(JsonFieldType.NUMBER) + .description("참여자 ID"), + fieldWithPath("reports[0].memberName").type(JsonFieldType.STRING) + .description("참여자 이름"), + fieldWithPath("reports[0].isDeposited").type(JsonFieldType.BOOLEAN) .description("참여자 이름"), fieldWithPath("reports[0].price").type(JsonFieldType.NUMBER) .description("참여자 정산 금액") diff --git a/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java deleted file mode 100644 index ace03c5ef..000000000 --- a/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java +++ /dev/null @@ -1,66 +0,0 @@ -package server.haengdong.docs; - -import static org.hamcrest.Matchers.equalTo; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; -import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; -import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; -import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; -import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.http.MediaType; -import org.springframework.restdocs.payload.JsonFieldType; -import server.haengdong.application.MemberActionService; -import server.haengdong.application.response.CurrentMemberAppResponse; -import server.haengdong.presentation.MemberActionController; - -public class MemberActionControllerDocsTest extends RestDocsSupport { - - private final MemberActionService memberActionService = mock(MemberActionService.class); - - @Override - protected Object initController() { - return new MemberActionController(memberActionService); - } - - @DisplayName("현재 참여 인원을 조회합니다.") - @Test - void getCurrentMembers() throws Exception { - List<CurrentMemberAppResponse> currentMemberAppResponses = List.of( - new CurrentMemberAppResponse("소하"), new CurrentMemberAppResponse("토다리")); - - given(memberActionService.getCurrentMembers(any())).willReturn(currentMemberAppResponses); - - mockMvc.perform(get("/api/events/{eventId}/members/current", "망쵸토큰") - .accept(MediaType.APPLICATION_JSON)) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.memberNames[0]").value(equalTo("소하"))) - .andExpect(jsonPath("$.memberNames[1]").value(equalTo("토다리"))) - .andDo( - document("getCurrentMembers", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - responseFields( - fieldWithPath("memberNames").type(JsonFieldType.ARRAY) - .description("현재 탈주 가능한 참여 인원 이름 목록") - ) - ) - ); - } -} diff --git a/server/src/test/java/server/haengdong/docs/MemberControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/MemberControllerDocsTest.java new file mode 100644 index 000000000..2997ad4ee --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/MemberControllerDocsTest.java @@ -0,0 +1,120 @@ +package server.haengdong.docs; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.restdocs.payload.JsonFieldType; +import server.haengdong.application.MemberService; +import server.haengdong.application.response.MemberAppResponse; +import server.haengdong.application.response.MemberDepositAppResponse; +import server.haengdong.application.response.MembersDepositAppResponse; +import server.haengdong.presentation.MemberController; + +class MemberControllerDocsTest extends RestDocsSupport { + + private final MemberService memberService = mock(MemberService.class); + + @Override + protected Object initController() { + return new MemberController(memberService); + } + + @DisplayName("행사에 참여한 전체 인원을 조회한다.") + @Test + void findAllMembersTest() throws Exception { + List<MemberDepositAppResponse> members = List.of( + new MemberDepositAppResponse(1L, "감자", false), + new MemberDepositAppResponse(2L, "백호", true), + new MemberDepositAppResponse(3L, "이상", true) + ); + + MembersDepositAppResponse memberAppResponse = new MembersDepositAppResponse(members); + given(memberService.findAllMembers(anyString())).willReturn(memberAppResponse); + + mockMvc.perform(get("/api/events/{eventId}/members", "TOKEN")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").isArray()) + .andExpect(jsonPath("$.members[0].id").value(1L)) + .andExpect(jsonPath("$.members[0].name").value("감자")) + .andExpect(jsonPath("$.members[0].isDeposited").value(false)) + .andExpect(jsonPath("$.members[1].id").value(2L)) + .andExpect(jsonPath("$.members[1].name").value("백호")) + .andExpect(jsonPath("$.members[1].isDeposited").value(true)) + .andExpect(jsonPath("$.members[2].id").value(3L)) + .andExpect(jsonPath("$.members[2].name").value("이상")) + .andExpect(jsonPath("$.members[2].isDeposited").value(true)) + .andDo( + document("findAllMembers", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("행사에 참여 중인 전체 멤버 목록"), + fieldWithPath("members[0].id").type(JsonFieldType.NUMBER) + .description("멤버 ID"), + fieldWithPath("members[0].name").type(JsonFieldType.STRING) + .description("멤버 이름"), + fieldWithPath("members[0].isDeposited").type(JsonFieldType.BOOLEAN) + .description("입금 여부") + ) + ) + ); + } + + @DisplayName("현재 참여 인원을 조회합니다.") + @Test + void getCurrentMembers() throws Exception { + List<MemberAppResponse> members = List.of( + new MemberAppResponse(1L, "감자"), + new MemberAppResponse(2L, "백호") + ); + + given(memberService.getCurrentMembers(any())).willReturn(members); + + mockMvc.perform(get("/api/events/{eventId}/members/current", "TOKEN")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").isArray()) + .andExpect(jsonPath("$.members[0].id").value(1L)) + .andExpect(jsonPath("$.members[0].name").value("감자")) + .andExpect(jsonPath("$.members[1].id").value(2L)) + .andExpect(jsonPath("$.members[1].name").value("백호")) + .andDo( + document("getCurrentMembers", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("현재 행사에 참여 중인 멤버 목록"), + fieldWithPath("members[0].id").type(JsonFieldType.NUMBER) + .description("멤버 ID"), + fieldWithPath("members[0].name").type(JsonFieldType.STRING) + .description("멤버 이름") + ) + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/domain/action/BillActionTest.java b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java deleted file mode 100644 index d66202663..000000000 --- a/server/src/test/java/server/haengdong/domain/action/BillActionTest.java +++ /dev/null @@ -1,86 +0,0 @@ -package server.haengdong.domain.action; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.assertAll; -import static server.haengdong.support.fixture.Fixture.BILL_ACTION; -import static server.haengdong.support.fixture.Fixture.EVENT1; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; -import server.haengdong.exception.HaengdongException; -import server.haengdong.support.fixture.Fixture; - -class BillActionTest { - - @DisplayName("지출 내역 제목의 앞뒤 공백을 제거한 길이가 1 ~ 30자가 아니면 지출을 생성할 수 없다.") - @ParameterizedTest - @ValueSource(strings = {"", " ", "1234567890123456789012345678901"}) - void validateTitle(String title) { - Sequence sequence = new Sequence(1L); - Long price = 100L; - - assertThatThrownBy(() -> new BillAction(EVENT1, sequence, title, price)) - .isInstanceOf(HaengdongException.class) - .hasMessage("앞뒤 공백을 제거한 지출 내역 제목은 1 ~ 30자여야 합니다."); - } - - @DisplayName("금액이 10,000,000 이하의 자연수가 아니면 지출을 생성할 수 없다.") - @ParameterizedTest - @ValueSource(longs = {0, 10_000_001, 20_000_000}) - void validatePrice(long price) { - Sequence sequence = new Sequence(1L); - String title = "title"; - - assertThatThrownBy(() -> new BillAction(EVENT1, sequence, title, price)) - .isInstanceOf(HaengdongException.class) - .hasMessage("지출 금액은 10,000,000 이하의 자연수여야 합니다."); - } - - @DisplayName("지출 내역을 올바르게 생성한다.") - @Test - void createBillAction() { - Sequence sequence = new Sequence(1L); - String title = "title"; - Long price = 1_000L; - - BillAction billAction = new BillAction(EVENT1, sequence, title, price); - - assertAll( - () -> assertThat(billAction.getSequence().getValue()).isEqualTo(1L), - () -> assertThat(billAction.getTitle()).isEqualTo(title), - () -> assertThat(billAction.getPrice()).isEqualTo(price) - ); - } - - @DisplayName("지출 액션에 멤버별 고정 금액이 설정되어 있는지 확인한다.") - @Test - void isFixed1() { - BillAction fixedBillAction = Fixture.createBillAction(EVENT1, 1L, "인생네컷", 2_000L); - - List<BillActionDetail> unfixedBillActionDetails = List.of( - new BillActionDetail(BILL_ACTION, "감자", 1_000L, false), - new BillActionDetail(BILL_ACTION, "고구마", 1_000L, false) - ); - fixedBillAction.addDetails(unfixedBillActionDetails); - - assertThat(fixedBillAction.isFixed()).isEqualTo(false); - } - - @DisplayName("지출 액션에 멤버별 고정 금액이 설정되어 있는지 확인한다.") - @Test - void isFixed2() { - BillAction fixedBillAction = Fixture.createBillAction(EVENT1, 1L, "인생네컷", 5_000L); - - List<BillActionDetail> unfixedBillActionDetails = List.of( - new BillActionDetail(BILL_ACTION, "감자", 4_000L, true), - new BillActionDetail(BILL_ACTION, "고구마", 1_000L, true) - ); - fixedBillAction.addDetails(unfixedBillActionDetails); - - assertThat(fixedBillAction.isFixed()).isEqualTo(true); - } -} diff --git a/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java b/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java deleted file mode 100644 index 95eab19cc..000000000 --- a/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java +++ /dev/null @@ -1,97 +0,0 @@ -package server.haengdong.domain.action; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; -import static server.haengdong.domain.action.MemberActionStatus.IN; -import static server.haengdong.domain.action.MemberActionStatus.OUT; - -import java.util.List; -import java.util.Set; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import server.haengdong.domain.event.Event; -import server.haengdong.exception.HaengdongException; -import server.haengdong.support.fixture.Fixture; - -class CurrentMembersTest { - - @DisplayName("인원 변동 이력으로 현재 참여 인원을 계산한다.") - @Test - void of() { - Event event = Fixture.EVENT1; - List<MemberAction> memberActions = List.of( - Fixture.createMemberAction(event, 1L, "망쵸", IN), - Fixture.createMemberAction(event, 2L, "백호", IN), - Fixture.createMemberAction(event, 3L, "백호", OUT), - Fixture.createMemberAction(event, 4L, "웨디", IN) - ); - - CurrentMembers currentMembers = CurrentMembers.of(memberActions); - - assertThat(currentMembers.getMembers()) - .containsExactlyInAnyOrder("망쵸", "웨디"); - } - - @DisplayName("인원 변동 액션의 상태가 IN이면 현재 인원에 추가한다.") - @Test - void addMemberAction1() { - CurrentMembers currentMembers = new CurrentMembers(); - Event event = Fixture.EVENT1; - MemberAction memberAction = Fixture.createMemberAction(event, 1L, "웨디", IN); - - CurrentMembers addedCurrentMembers = currentMembers.addMemberAction(memberAction); - Set<String> members = addedCurrentMembers.getMembers(); - - assertThat(members).hasSize(1) - .containsExactly("웨디"); - } - - @DisplayName("인원 변동 액션의 상태가 OUT이면 현재 인원에서 제외한다.") - @Test - void addMemberAction2() { - Event event = Fixture.EVENT1; - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "웨디", IN); - CurrentMembers currentMembers = new CurrentMembers().addMemberAction(memberAction1); - MemberAction memberAction2 = Fixture.createMemberAction(event, 1L, "웨디", OUT); - - CurrentMembers addedCurrentMembers = currentMembers.addMemberAction(memberAction2); - - assertThat(addedCurrentMembers.getMembers()).hasSize(0); - } - - @DisplayName("현재 참여중인 인원은 나갈 수 있다.") - @Test - void validate1() { - CurrentMembers currentMembers = new CurrentMembers(Set.of("토다리")); - - assertThatCode(() -> currentMembers.validate("토다리", OUT)) - .doesNotThrowAnyException(); - } - - @DisplayName("현재 참여중이지 않은 인원은 들어올 수 있다.") - @Test - void validate2() { - CurrentMembers currentMembers = new CurrentMembers(Set.of("쿠키")); - - assertThatCode(() -> currentMembers.validate("토다리", IN)) - .doesNotThrowAnyException(); - } - - @DisplayName("현재 참여중인 인원은 들어올 수 없다.") - @Test - void validate3() { - CurrentMembers currentMembers = new CurrentMembers(Set.of("토다리")); - - assertThatCode(() -> currentMembers.validate("토다리", IN)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("현재 참여중이지 않은 인원은 나갈 수 없다.") - @Test - void validate4() { - CurrentMembers currentMembers = new CurrentMembers(Set.of("쿠키")); - - assertThatCode(() -> currentMembers.validate("토다리", OUT)) - .isInstanceOf(HaengdongException.class); - } -} diff --git a/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java b/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java deleted file mode 100644 index 4a009d2df..000000000 --- a/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java +++ /dev/null @@ -1,56 +0,0 @@ -package server.haengdong.domain.action; - -import static org.assertj.core.api.Assertions.assertThat; -import static server.haengdong.domain.action.MemberActionStatus.IN; -import static server.haengdong.domain.action.MemberActionStatus.OUT; -import static server.haengdong.support.fixture.Fixture.BILL_ACTION; - -import java.util.List; -import java.util.Map; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import server.haengdong.domain.event.Event; -import server.haengdong.support.fixture.Fixture; - -class MemberBillReportTest { - - @DisplayName("액션 목록으로 참가자 정산 리포트를 생성한다.") - @Test - void createByActions() { - Event event = Fixture.EVENT1; - List<BillAction> billActions = List.of( - Fixture.createBillAction(event, 4L, "뽕족", 60_000L), - Fixture.createBillAction(event, 7L, "인생네컷", 20_000L) - ); - billActions.get(0).addDetails( - List.of( - new BillActionDetail(BILL_ACTION, "소하", 10_000L, false), - new BillActionDetail(BILL_ACTION, "감자", 40_000L, true), - new BillActionDetail(BILL_ACTION, "쿠키", 10_000L, false) - ) - ); - billActions.get(1).addDetails( - List.of( - new BillActionDetail(BILL_ACTION, "소하", 5_000L, true), - new BillActionDetail(BILL_ACTION, "쿠키", 15_000L, true) - ) - ); - List<MemberAction> memberActions = List.of( - Fixture.createMemberAction(event, 1L, "소하", IN), - Fixture.createMemberAction(event, 2L, "감자", IN), - Fixture.createMemberAction(event, 3L, "쿠키", IN), - Fixture.createMemberAction(event, 5L, "감자", OUT) - ); - - MemberBillReport memberBillReport = MemberBillReport.createByActions(billActions, memberActions); - - assertThat(memberBillReport.getReports()) - .containsAllEntriesOf( - Map.of( - "감자", 40_000L, - "쿠키", 25_000L, - "소하", 15_000L - ) - ); - } -} diff --git a/server/src/test/java/server/haengdong/domain/action/SequenceTest.java b/server/src/test/java/server/haengdong/domain/action/SequenceTest.java deleted file mode 100644 index d2277d593..000000000 --- a/server/src/test/java/server/haengdong/domain/action/SequenceTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package server.haengdong.domain.action; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -class SequenceTest { - - @DisplayName("액션의 초기 순서번호는 1이다.") - @Test - void createFirst() { - Sequence sequence = Sequence.createFirst(); - - assertThat(sequence.getValue()).isOne(); - } - - @DisplayName("현재 액션의 다음 액션의 순서는 1만큼 증가한다.") - @Test - void next() { - Sequence sequence = new Sequence(2L); - - Sequence nextAction = sequence.next(); - - assertThat(nextAction.getValue()).isEqualTo(3L); - } -} diff --git a/server/src/test/java/server/haengdong/domain/bill/BillTest.java b/server/src/test/java/server/haengdong/domain/bill/BillTest.java new file mode 100644 index 000000000..d1c2e3d8c --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/bill/BillTest.java @@ -0,0 +1,98 @@ +package server.haengdong.domain.bill; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static server.haengdong.support.fixture.Fixture.EVENT1; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import server.haengdong.domain.member.Member; +import server.haengdong.exception.HaengdongException; + +class BillTest { + + @DisplayName("지출 내역 제목의 앞뒤 공백을 제거한 길이가 1 ~ 30자가 아니면 지출을 생성할 수 없다.") + @ParameterizedTest + @ValueSource(strings = {"", " ", "1234567890123456789012345678901"}) + void validateTitle(String title) { + Long price = 100L; + + assertThatThrownBy(() -> new Bill(EVENT1, title, price)) + .isInstanceOf(HaengdongException.class) + .hasMessage("앞뒤 공백을 제거한 지출 내역 제목은 1 ~ 30자여야 합니다."); + } + + @DisplayName("금액이 10,000,000 이하의 자연수가 아니면 지출을 생성할 수 없다.") + @ParameterizedTest + @ValueSource(longs = {0, 10_000_001, 20_000_000}) + void validatePrice(long price) { + String title = "title"; + + assertThatThrownBy(() -> new Bill(EVENT1, title, price)) + .isInstanceOf(HaengdongException.class) + .hasMessage("지출 금액은 10,000,000 이하의 자연수여야 합니다."); + } + + @DisplayName("지출 내역을 올바르게 생성한다.") + @Test + void createBill() { + String title = "title"; + Long price = 1_000L; + + Bill bill = new Bill(EVENT1, title, price); + + assertAll( + () -> assertThat(bill.getTitle()).isEqualTo(title), + () -> assertThat(bill.getPrice()).isEqualTo(price) + ); + } + + @DisplayName("지출에 멤버별 고정 금액이 설정되어 있는지 확인한다.") + @Test + void isFixed1() { + List<Member> members = List.of(new Member(EVENT1, "감자"), new Member(EVENT1, "고구마")); + Bill fixedBill = Bill.create(EVENT1, "인생네컷", 2_000L, members); + + assertThat(fixedBill.isFixed()).isEqualTo(false); + } + + @DisplayName("같은 멤버 목록을 가지고 있는지 비교한다.") + @Test + void isSameMember1() { + Member member1 = new Member(1L, EVENT1, "감자", false); + Member member2 = new Member(2L, EVENT1, "고구마", false); + Member member3 = new Member(3L, EVENT1, "당근", false); + + List<Member> members1 = List.of(member1, member2, member3); + List<Member> members2 = List.of(member2, member3, member1); + + Bill bill1 = Bill.create(EVENT1, "뽕족", 20_000L, members1); + Bill bill2 = Bill.create(EVENT1, "인생네컷", 30_000L, members2); + + boolean isSameMembers = bill1.isSameMembers(bill2); + + assertThat(isSameMembers).isTrue(); + } + + @DisplayName("같은 멤버 목록을 가지고 있는지 비교한다.") + @Test + void isSameMember2() { + Member member1 = new Member(1L, EVENT1, "감자", false); + Member member2 = new Member(2L, EVENT1, "고구마", false); + Member member3 = new Member(3L, EVENT1, "당근", false); + + List<Member> members1 = List.of(member1, member2, member3); + List<Member> members2 = List.of(member2, member1); + + Bill bill1 = Bill.create(EVENT1, "뽕족", 20_000L, members1); + Bill bill2 = Bill.create(EVENT1, "인생네컷", 30_000L, members2); + + boolean isSameMembers = bill1.isSameMembers(bill2); + + assertThat(isSameMembers).isFalse(); + } +} diff --git a/server/src/test/java/server/haengdong/domain/event/EventTest.java b/server/src/test/java/server/haengdong/domain/event/EventTest.java index 12c0c0569..83cd700a0 100644 --- a/server/src/test/java/server/haengdong/domain/event/EventTest.java +++ b/server/src/test/java/server/haengdong/domain/event/EventTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -25,7 +26,7 @@ void createSuccessTest(String eventName) { void createFailTest1(String eventName) { assertThatCode(() -> new Event(eventName, "1234", "TEST_TOKEN")) .isInstanceOf(HaengdongException.class) - .hasMessage(String.format("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s", eventName)); + .hasMessage("행사 이름에는 공백 문자가 연속될 수 없습니다."); } @DisplayName("이름이 1자 미만이거나 20자 초과인 경우 예외가 발생한다.") @@ -34,7 +35,7 @@ void createFailTest1(String eventName) { void createFilTest2(String eventName) { assertThatCode(() -> new Event(eventName, "1234", "TEST_TOKEN")) .isInstanceOf(HaengdongException.class) - .hasMessage(String.format("행사 이름은 1자 이상 20자 이하만 입력 가능합니다. 입력한 이름 길이 : %d", eventName.length())); + .hasMessage("행사 이름은 1자 이상 20자 이하만 입력 가능합니다."); } @DisplayName("비밀번호는 4자리 숫자 입니다.") @@ -62,4 +63,73 @@ void isNotSamePassword1() { assertThat(event.isPasswordMismatch(rawPassword)).isTrue(); } + + @DisplayName("이름을 수정한다.") + @Test + void renameTest() { + Event event = new Event("이름", "1234", "TEST_TOKEN"); + + event.rename("새로운 이름"); + + assertThat(event.getName()).isEqualTo("새로운 이름"); + } + + @DisplayName("계좌 정보에 은행 이름과 계좌 번호가 모두 포함된다.") + @Test + void changeAccountTest() { + Event event = new Event("이름", "1234", "TEST_TOKEN"); + + event.changeAccount("토스뱅크", "12345678"); + + assertThat(event.getAccount()).isEqualTo("토스뱅크 12345678"); + } + + @DisplayName("계좌 정보에 은행 이름과 계좌 번호가 모두 포함되지 않으면 예외가 발생한다.") + @Test + void changeAccountTest1() { + Event event = new Event("이름", "1234", "TEST_TOKEN"); + + assertThatThrownBy(() -> event.changeAccount("행대뱅크", "")) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("지원하는 은행이면 예외가 발생하지 않는다.") + @ParameterizedTest + @ValueSource(strings = {"토스뱅크", "KB국민은행"}) + void changeAccountTest2(String bankName) { + Event event = new Event("이름", "1234", "TEST_TOKEN"); + + assertThatCode(() -> event.changeAccount(bankName, "12345678")) + .doesNotThrowAnyException(); + } + + @DisplayName("지원하지 않는 은행이면 예외가 발생한다.") + @ParameterizedTest + @ValueSource(strings = {"행대뱅크", "토스 뱅크", "망쵸뱅크", "KB 국민은행"}) + void changeAccountTest3(String bankName) { + Event event = new Event("이름", "1234", "TEST_TOKEN"); + + assertThatThrownBy(() -> event.changeAccount(bankName, "12345678")) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("계좌 번호가 8자 이상 30자 이하면 예외가 발생하지 않는다.") + @ParameterizedTest + @ValueSource(strings = {"12345678", "123456789012345678901234567890"}) + void changeAccountTest4(String accountNumber) { + Event event = new Event("이름", "1234", "TEST_TOKEN"); + + assertThatCode(() -> event.changeAccount("토스뱅크", accountNumber)) + .doesNotThrowAnyException(); + } + + @DisplayName("계좌 번호가 8자 미만 30자 초과면 예외가 발생한다.") + @ParameterizedTest + @ValueSource(strings = {"", " ", "1234567", "1234567890123456789012345678901"}) + void changeAccountTest5(String accountNumber) { + Event event = new Event("이름", "1234", "TEST_TOKEN"); + + assertThatThrownBy(() -> event.changeAccount("토스뱅크", accountNumber)) + .isInstanceOf(HaengdongException.class); + } } diff --git a/server/src/test/java/server/haengdong/domain/member/MemberBillReportTest.java b/server/src/test/java/server/haengdong/domain/member/MemberBillReportTest.java new file mode 100644 index 000000000..ca33603a1 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/member/MemberBillReportTest.java @@ -0,0 +1,41 @@ +package server.haengdong.domain.member; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.event.Event; +import server.haengdong.support.fixture.Fixture; + +class MemberBillReportTest { + + @DisplayName("지출 목록으로 참가자 정산 리포트를 생성한다.") + @Test + void createByBills() { + Event event = Fixture.EVENT1; + Member member1 = new Member(1L, event, "소하", false); + Member member2 = new Member(2L, event, "감자", false); + Member member3 = new Member(3L, event, "쿠키", false); + Member member4 = new Member(4L, event, "고구마", false); + List<Member> members = List.of(member1, member2, member3, member4); + List<Bill> bills = List.of( + Bill.create(event, "뽕족", 60_000L, members), + Bill.create(event, "인생네컷", 20_000L, members) + ); + + MemberBillReport memberBillReport = MemberBillReport.createByBills(bills); + + assertThat(memberBillReport.getReports()) + .containsAllEntriesOf( + Map.of( + member1, 20_000L, + member2, 20_000L, + member3, 20_000L, + member4, 20_000L + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/domain/step/StepTest.java b/server/src/test/java/server/haengdong/domain/step/StepTest.java new file mode 100644 index 000000000..5c5631840 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/step/StepTest.java @@ -0,0 +1,50 @@ +package server.haengdong.domain.step; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static server.haengdong.support.fixture.Fixture.EVENT1; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.member.Member; +import server.haengdong.exception.HaengdongException; + +class StepTest { + + @DisplayName("회원 구성이 같은 지출은 Step에 추가될 수 있다.") + @Test + void add1() { + Member member1 = new Member(1L, EVENT1, "감자", false); + Member member2 = new Member(2L, EVENT1, "고구마", false); + Member member3 = new Member(3L, EVENT1, "당근", false); + Member member4 = new Member(4L, EVENT1, "양파", false); + Bill bill1 = Bill.create(EVENT1, "뽕족", 10_000L, List.of(member1, member2, member3, member4)); + Step step = Step.of(bill1); + + Bill bill2 = Bill.create(EVENT1, "인생네컷", 5_000L, List.of(member2, member3, member1, member4)); + + step.add(bill2); + + List<Bill> bills = step.getBills(); + + assertThat(bills).hasSize(2); + } + + @DisplayName("회원 구성이 댜른 지출은 Step에 추가될 수 없다.") + @Test + void add2() { + Member member1 = new Member(1L, EVENT1, "감자", false); + Member member2 = new Member(2L, EVENT1, "고구마", false); + Member member3 = new Member(3L, EVENT1, "당근", false); + Member member4 = new Member(4L, EVENT1, "양파", false); + Bill bill1 = Bill.create(EVENT1, "뽕족", 10_000L, List.of(member1, member2, member3, member4)); + Step step = Step.of(bill1); + + Bill bill2 = Bill.create(EVENT1, "인생네컷", 5_000L, List.of(member2, member3, member1)); + + assertThatThrownBy(() -> step.add(bill2)) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/domain/step/StepsTest.java b/server/src/test/java/server/haengdong/domain/step/StepsTest.java new file mode 100644 index 000000000..799cb0d4c --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/step/StepsTest.java @@ -0,0 +1,48 @@ +package server.haengdong.domain.step; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; +import static server.haengdong.support.fixture.Fixture.EVENT1; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.member.Member; + +class StepsTest { + + @DisplayName("지출 목록 순으로 같은 회원 구성인 경우 같은 Step으로 묶는다.") + @Test + void of() { + Member member1 = new Member(1L, EVENT1, "감자", false); + Member member2 = new Member(2L, EVENT1, "고구마", false); + Member member3 = new Member(3L, EVENT1, "당근", false); + Member member4 = new Member(4L, EVENT1, "양파", false); + Bill bill1 = Bill.create(EVENT1, "뽕족", 10_000L, List.of(member1, member2)); + Bill bill2 = Bill.create(EVENT1, "용용선생", 20_000L, List.of(member2, member1)); + Bill bill3 = Bill.create(EVENT1, "보승회관", 30_000L, List.of(member1, member2, member3)); + Bill bill4 = Bill.create(EVENT1, "감자", 40_000L, List.of(member1, member2, member3, member4)); + Bill bill5 = Bill.create(EVENT1, "인생네컷", 5_000L, List.of(member2, member3, member1, member4)); + List<Bill> bills = List.of(bill1, bill2, bill3, bill4, bill5); + + Steps step = Steps.of(bills); + + List<Step> steps = step.getSteps(); + assertAll( + () -> assertThat(steps).hasSize(3), + () -> assertThat(steps.get(0).getBills()).hasSize(2) + .containsExactly(bill1, bill2), + () -> assertThat(steps.get(0).getMembers()).hasSize(2) + .containsExactly(member1, member2), + () -> assertThat(steps.get(1).getBills()).hasSize(1) + .containsExactly(bill3), + () -> assertThat(steps.get(1).getMembers()).hasSize(3) + .containsExactly(member1, member2, member3), + () -> assertThat(steps.get(2).getBills()).hasSize(2) + .containsExactly(bill4, bill5), + () -> assertThat(steps.get(2).getMembers()).hasSize(4) + .containsExactly(member1, member2, member3, member4) + ); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java deleted file mode 100644 index 0fa3311b3..000000000 --- a/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java +++ /dev/null @@ -1,4 +0,0 @@ -package server.haengdong.presentation; - -class ActionControllerTest extends ControllerTestSupport { -} diff --git a/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java deleted file mode 100644 index f4e65d4f0..000000000 --- a/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package server.haengdong.presentation; - -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.BDDMockito.given; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import server.haengdong.application.response.BillActionDetailAppResponse; -import server.haengdong.application.response.BillActionDetailsAppResponse; - -class BillActionDetailControllerTest extends ControllerTestSupport { - - @DisplayName("참여자별 지출 금액을 조회한다.") - @Test - void findBillActionDetails() throws Exception { - BillActionDetailsAppResponse appResponse = new BillActionDetailsAppResponse( - List.of(new BillActionDetailAppResponse("토다리", 1000L, false))); - given(billActionDetailService.findBillActionDetails(anyString(), anyLong())) - .willReturn(appResponse); - - mockMvc.perform(get("/api/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.members").isArray()) - .andExpect(jsonPath("$.members[0].name").value("토다리")) - .andExpect(jsonPath("$.members[0].price").value(1000L)); - } -} diff --git a/server/src/test/java/server/haengdong/presentation/BillControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillControllerTest.java new file mode 100644 index 000000000..10d7fd1f6 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/BillControllerTest.java @@ -0,0 +1,66 @@ +package server.haengdong.presentation; + +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.application.response.BillAppResponse; +import server.haengdong.application.response.BillDetailAppResponse; +import server.haengdong.application.response.BillDetailsAppResponse; +import server.haengdong.application.response.MemberAppResponse; +import server.haengdong.application.response.StepAppResponse; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.member.Member; +import server.haengdong.support.fixture.Fixture; + +class BillControllerTest extends ControllerTestSupport { + + @DisplayName("전체 지출 내역을 조회한다.") + @Test + void findBills() throws Exception { + Bill bill = Fixture.BILL1; + List<BillAppResponse> bills = List.of(BillAppResponse.of(bill)); + + Member member = Fixture.MEMBER1; + List<MemberAppResponse> members = List.of(MemberAppResponse.of(member)); + + StepAppResponse stepAppResponse = new StepAppResponse(bills, members); + given(billService.findSteps(anyString())).willReturn(List.of(stepAppResponse)); + + mockMvc.perform(get("/api/events/{eventId}/bills", "token")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.steps").isArray()) + .andExpect(jsonPath("$.steps[0].bills").isArray()) + .andExpect(jsonPath("$.steps[0].bills[0].id").value(bill.getId())) + .andExpect(jsonPath("$.steps[0].bills[0].title").value(bill.getTitle())) + .andExpect(jsonPath("$.steps[0].bills[0].price").value(bill.getPrice())) + .andExpect(jsonPath("$.steps[0].bills[0].isFixed").value(bill.isFixed())) + .andExpect(jsonPath("$.steps[0].members").isArray()) + .andExpect(jsonPath("$.steps[0].members[0].id").value(member.getId())) + .andExpect(jsonPath("$.steps[0].members[0].name").value(member.getName())); + } + + @DisplayName("참여자별 지출 금액을 조회한다.") + @Test + void findBillActionDetails() throws Exception { + BillDetailsAppResponse appResponse = new BillDetailsAppResponse( + List.of(new BillDetailAppResponse(1L, "토다리", 1000L, false))); + given(billService.findBillDetails(anyString(), anyLong())).willReturn(appResponse); + + mockMvc.perform(get("/api/events/{eventId}/bills/{billId}/details", "TOKEN", 1L)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").isArray()) + .andExpect(jsonPath("$.members[0].id").value(1L)) + .andExpect(jsonPath("$.members[0].memberName").value("토다리")) + .andExpect(jsonPath("$.members[0].price").value(1000L)) + .andExpect(jsonPath("$.members[0].isFixed").value(false)); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java b/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java index f5964e897..6ba5540d5 100644 --- a/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java +++ b/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java @@ -9,22 +9,21 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import server.haengdong.application.AuthService; -import server.haengdong.application.BillActionDetailService; -import server.haengdong.application.BillActionService; +import server.haengdong.application.BillService; import server.haengdong.application.EventService; -import server.haengdong.application.MemberActionService; -import server.haengdong.presentation.admin.AdminBillActionController; +import server.haengdong.application.MemberService; +import server.haengdong.presentation.admin.AdminBillController; import server.haengdong.presentation.admin.AdminEventController; -import server.haengdong.presentation.admin.AdminMemberActionController; +import server.haengdong.presentation.admin.AdminMemberController; @WebMvcTest( controllers = { AdminEventController.class, - AdminBillActionController.class, - AdminMemberActionController.class, + AdminBillController.class, + AdminMemberController.class, EventController.class, - MemberActionController.class, - BillActionDetailController.class + MemberController.class, + BillController.class }, excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {WebMvcConfigurer.class})} ) @@ -43,11 +42,8 @@ public abstract class ControllerTestSupport { protected AuthService authService; @MockBean - protected MemberActionService memberActionService; + protected MemberService memberService; @MockBean - protected BillActionService billActionService; - - @MockBean - protected BillActionDetailService billActionDetailService; + protected BillService billService; } diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java index a58924a32..f1f11d4a6 100644 --- a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java @@ -2,10 +2,9 @@ import static org.hamcrest.Matchers.equalTo; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.given; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; @@ -20,7 +19,6 @@ import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; import server.haengdong.application.response.MemberBillReportAppResponse; -import server.haengdong.application.response.MembersAppResponse; import server.haengdong.presentation.request.EventLoginRequest; import server.haengdong.presentation.request.EventSaveRequest; @@ -31,7 +29,7 @@ class EventControllerTest extends ControllerTestSupport { @Test void findEventTest() throws Exception { String eventId = "망쵸토큰"; - EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식"); + EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식", "토스 1231245"); given(eventService.findEvent(eventId)).willReturn(eventDetailAppResponse); mockMvc.perform(get("/api/events/{eventId}", eventId)) @@ -40,25 +38,13 @@ void findEventTest() throws Exception { .andExpect(jsonPath("$.eventName").value("행동대장 회식")); } - @DisplayName("행사에 참여한 전체 인원을 중복 없이 조회한다.") - @Test - void findAllMembersTest() throws Exception { - MembersAppResponse memberAppResponse = new MembersAppResponse(List.of("토다리", "쿠키")); - given(eventService.findAllMembers(anyString())).willReturn(memberAppResponse); - - mockMvc.perform(get("/api/events/{eventId}/members", "TOKEN")) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.memberNames").isArray()) - .andExpect(jsonPath("$.memberNames[0]").value("토다리")) - .andExpect(jsonPath("$.memberNames[1]").value("쿠키")); - } - @DisplayName("참여자별 정산 현황을 조회한다.") @Test void getMemberBillReports() throws Exception { List<MemberBillReportAppResponse> memberBillReportAppResponses = List.of( - new MemberBillReportAppResponse("소하", 20_000L), new MemberBillReportAppResponse("토다리", 200_000L)); + new MemberBillReportAppResponse(1L, "소하", false, 20_000L), + new MemberBillReportAppResponse(2L, "토다리", false, 200_000L) + ); given(eventService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); @@ -66,9 +52,13 @@ void getMemberBillReports() throws Exception { .accept(MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].name").value(equalTo("소하"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].memberId").value(equalTo(1))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].memberName").value(equalTo("소하"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].isDeposited").value(equalTo(false))) .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].price").value(equalTo(20_000))) - .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].name").value(equalTo("토다리"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].memberId").value(equalTo(2))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].memberName").value(equalTo("토다리"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].isDeposited").value(equalTo(false))) .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].price").value(equalTo(200_000))); } diff --git a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java deleted file mode 100644 index a2fd05437..000000000 --- a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java +++ /dev/null @@ -1,34 +0,0 @@ -package server.haengdong.presentation; - -import static org.hamcrest.Matchers.equalTo; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.http.MediaType; -import server.haengdong.application.response.CurrentMemberAppResponse; - -class MemberActionControllerTest extends ControllerTestSupport { - - @DisplayName("현재 참여 인원을 조회합니다.") - @Test - void getCurrentMembers() throws Exception { - List<CurrentMemberAppResponse> currentMemberAppResponses = List.of( - new CurrentMemberAppResponse("소하"), new CurrentMemberAppResponse("토다리")); - - given(memberActionService.getCurrentMembers(any())).willReturn(currentMemberAppResponses); - - mockMvc.perform(get("/api/events/{eventId}/members/current", "망쵸토큰") - .accept(MediaType.APPLICATION_JSON)) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.memberNames[0]").value(equalTo("소하"))) - .andExpect(jsonPath("$.memberNames[1]").value(equalTo("토다리"))); - } -} diff --git a/server/src/test/java/server/haengdong/presentation/MemberControllerTest.java b/server/src/test/java/server/haengdong/presentation/MemberControllerTest.java new file mode 100644 index 000000000..ff824831b --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/MemberControllerTest.java @@ -0,0 +1,77 @@ +package server.haengdong.presentation; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.MEMBER1; +import static server.haengdong.support.fixture.Fixture.MEMBER2; +import static server.haengdong.support.fixture.Fixture.MEMBER3; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import server.haengdong.application.response.MemberAppResponse; +import server.haengdong.application.response.MemberDepositAppResponse; +import server.haengdong.application.response.MembersDepositAppResponse; +import server.haengdong.domain.member.Member; + +class MemberControllerTest extends ControllerTestSupport { + + @DisplayName("행사에 참여한 전체 인원을 조회한다.") + @Test + void findAllMembersTest() throws Exception { + Member member1 = MEMBER1; + Member member2 = MEMBER2; + Member member3 = MEMBER3; + List<MemberDepositAppResponse> members = List.of( + MemberDepositAppResponse.of(member1), + MemberDepositAppResponse.of(member2), + MemberDepositAppResponse.of(member3) + ); + + MembersDepositAppResponse memberAppResponse = new MembersDepositAppResponse(members); + given(memberService.findAllMembers(anyString())).willReturn(memberAppResponse); + + mockMvc.perform(get("/api/events/{eventId}/members", "TOKEN")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").isArray()) + .andExpect(jsonPath("$.members[0].id").value(member1.getId())) + .andExpect(jsonPath("$.members[0].name").value(member1.getName())) + .andExpect(jsonPath("$.members[0].isDeposited").value(member1.isDeposited())) + .andExpect(jsonPath("$.members[1].id").value(member2.getId())) + .andExpect(jsonPath("$.members[1].name").value(member2.getName())) + .andExpect(jsonPath("$.members[1].isDeposited").value(member2.isDeposited())) + .andExpect(jsonPath("$.members[2].id").value(member3.getId())) + .andExpect(jsonPath("$.members[2].name").value(member3.getName())) + .andExpect(jsonPath("$.members[2].isDeposited").value(member3.isDeposited())); + } + + @DisplayName("현재 참여 인원을 조회합니다.") + @Test + void getCurrentMembers() throws Exception { + Member member1 = MEMBER1; + Member member2 = MEMBER2; + List<MemberAppResponse> members = List.of( + MemberAppResponse.of(member1), + MemberAppResponse.of(member2) + ); + + given(memberService.getCurrentMembers(any())).willReturn(members); + + mockMvc.perform(get("/api/events/{eventId}/members/current", "TOKEN") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").isArray()) + .andExpect(jsonPath("$.members[0].id").value(member1.getId())) + .andExpect(jsonPath("$.members[0].name").value(member1.getName())) + .andExpect(jsonPath("$.members[1].id").value(member2.getId())) + .andExpect(jsonPath("$.members[1].name").value(member2.getName())); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/admin/AdminBillActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/admin/AdminBillControllerTest.java similarity index 58% rename from server/src/test/java/server/haengdong/presentation/admin/AdminBillActionControllerTest.java rename to server/src/test/java/server/haengdong/presentation/admin/AdminBillControllerTest.java index 7e401d9b0..f776a1624 100644 --- a/server/src/test/java/server/haengdong/presentation/admin/AdminBillActionControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/admin/AdminBillControllerTest.java @@ -1,12 +1,14 @@ package server.haengdong.presentation.admin; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doThrow; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; import java.util.List; import org.junit.jupiter.api.DisplayName; @@ -15,29 +17,26 @@ import server.haengdong.exception.HaengdongErrorCode; import server.haengdong.exception.HaengdongException; import server.haengdong.presentation.ControllerTestSupport; -import server.haengdong.presentation.request.BillActionDetailUpdateRequest; -import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; -import server.haengdong.presentation.request.BillActionSaveRequest; -import server.haengdong.presentation.request.BillActionUpdateRequest; -import server.haengdong.presentation.request.BillActionsSaveRequest; +import server.haengdong.presentation.request.BillDetailUpdateRequest; +import server.haengdong.presentation.request.BillDetailsUpdateRequest; +import server.haengdong.presentation.request.BillSaveRequest; +import server.haengdong.presentation.request.BillUpdateRequest; -class AdminBillActionControllerTest extends ControllerTestSupport { +class AdminBillControllerTest extends ControllerTestSupport { @DisplayName("지출 내역을 생성한다.") @Test void saveAllBillAction() throws Exception { - BillActionsSaveRequest request = new BillActionsSaveRequest( - List.of( - new BillActionSaveRequest("뽕족", 10_000L), - new BillActionSaveRequest("인생맥주", 10_000L) - ) - ); + List<Long> members = List.of(1L, 2L); + BillSaveRequest request = new BillSaveRequest("뽕족", 10_000L, members); + String requestBody = objectMapper.writeValueAsString(request); String eventId = "쿠키토큰"; - mockMvc.perform(post("/api/admin/events/{eventId}/bill-actions", eventId) + mockMvc.perform(post("/api/admin/events/{eventId}/bills", eventId) .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + .content(requestBody) + .cookie(EVENT_COOKIE)) .andDo(print()) .andExpect(status().isOk()); } @@ -45,16 +44,13 @@ void saveAllBillAction() throws Exception { @DisplayName("title이 비어 있는 경우 지출 내역을 생성할 수 없다.") @Test void saveAllBillAction1() throws Exception { - BillActionsSaveRequest request = new BillActionsSaveRequest( - List.of( - new BillActionSaveRequest("", 10_000L), - new BillActionSaveRequest("인생맥주", 10_000L) - ) - ); + List<Long> members = List.of(1L, 2L); + BillSaveRequest request = new BillSaveRequest("", 10_000L, members); + String requestBody = objectMapper.writeValueAsString(request); String eventId = "소하토큰"; - mockMvc.perform(post("/api/admin/events/{eventId}/bill-actions", eventId) + mockMvc.perform(post("/api/admin/events/{eventId}/bills", eventId) .contentType(MediaType.APPLICATION_JSON) .content(requestBody)) .andDo(print()) @@ -64,14 +60,15 @@ void saveAllBillAction1() throws Exception { @DisplayName("지출 액션을 수정한다.") @Test void updateBillAction() throws Exception { - BillActionUpdateRequest request = new BillActionUpdateRequest("뽕족", 10_000L); + BillUpdateRequest request = new BillUpdateRequest("뽕족", 10_000L); String requestBody = objectMapper.writeValueAsString(request); String eventId = "웨디토큰"; - mockMvc.perform(put("/api/admin/events/{eventId}/bill-actions/{actionId}", eventId, 1L) + mockMvc.perform(put("/api/admin/events/{eventId}/bills/{billId}", eventId, 1L) .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + .content(requestBody) + .cookie(EVENT_COOKIE)) .andDo(print()) .andExpect(status().isOk()); } @@ -81,7 +78,7 @@ void updateBillAction() throws Exception { void deleteBillAction() throws Exception { String eventId = "토다리토큰"; - mockMvc.perform(delete("/api/admin/events/{eventId}/bill-actions/{actionId}", eventId, 1)) + mockMvc.perform(delete("/api/admin/events/{eventId}/bills/{billId}", eventId, 1)) .andDo(print()) .andExpect(status().isOk()); } @@ -91,9 +88,9 @@ void deleteBillAction() throws Exception { void deleteBillAction1() throws Exception { String eventId = "이상해토큰"; doThrow(new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)) - .when(billActionService).deleteBillAction(any(String.class), any(Long.class)); + .when(billService).deleteBill(any(String.class), any(Long.class)); - mockMvc.perform(delete("/api/admin/events/{eventId}/bill-actions/{actionId}", eventId, 1)) + mockMvc.perform(delete("/api/admin/events/{eventId}/bills/{billId}", eventId, 1)) .andDo(print()) .andExpect(status().isBadRequest()); } @@ -101,16 +98,16 @@ void deleteBillAction1() throws Exception { @DisplayName("참여자별 지출 금액을 수정한다.") @Test void updateBillActionDetailsTest() throws Exception { - List<BillActionDetailUpdateRequest> billActionDetailUpdateRequests = List.of( - new BillActionDetailUpdateRequest("소하", 10000L, true), - new BillActionDetailUpdateRequest("웨디", 20000L, true) + List<BillDetailUpdateRequest> billActionDetailUpdateRequests = List.of( + new BillDetailUpdateRequest(1L, 10000L, true), + new BillDetailUpdateRequest(2L, 20000L, true) ); - BillActionDetailsUpdateRequest request = new BillActionDetailsUpdateRequest( + BillDetailsUpdateRequest request = new BillDetailsUpdateRequest( billActionDetailUpdateRequests); String json = objectMapper.writeValueAsString(request); - mockMvc.perform(put("/api/admin/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L) + mockMvc.perform(put("/api/admin/events/{eventId}/bills/{billId}/details", "TOKEN", 1L) .contentType(MediaType.APPLICATION_JSON) .content(json)) .andDo(print()) diff --git a/server/src/test/java/server/haengdong/presentation/admin/AdminEventControllerTest.java b/server/src/test/java/server/haengdong/presentation/admin/AdminEventControllerTest.java index 3ce2422c6..df7b70e92 100644 --- a/server/src/test/java/server/haengdong/presentation/admin/AdminEventControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/admin/AdminEventControllerTest.java @@ -1,34 +1,29 @@ package server.haengdong.presentation.admin; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; import server.haengdong.presentation.ControllerTestSupport; -import server.haengdong.presentation.request.MemberNameUpdateRequest; -import server.haengdong.presentation.request.MemberNamesUpdateRequest; +import server.haengdong.presentation.request.EventUpdateRequest; class AdminEventControllerTest extends ControllerTestSupport { - @DisplayName("행사 참여 인원의 이름을 수정한다.") + @DisplayName("행사 정보를 수정한다.") @Test - void updateMember() throws Exception { + void updateEventTest() throws Exception { String token = "TOKEN"; - MemberNamesUpdateRequest memberNameUpdateRequest = new MemberNamesUpdateRequest(List.of( - new MemberNameUpdateRequest("토다링", "토쟁이"), - new MemberNameUpdateRequest("감자", "고구마") - )); + EventUpdateRequest eventUpdateRequest = new EventUpdateRequest("행동대장 비대위", "행대뱅크", "12345678"); - String requestBody = objectMapper.writeValueAsString(memberNameUpdateRequest); + String requestBody = objectMapper.writeValueAsString(eventUpdateRequest); - mockMvc.perform(put("/api/admin/events/{eventId}/members/nameChange", token) - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + mockMvc.perform(patch("/api/admin/events/{eventId}", token) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) .andDo(print()) .andExpect(status().isOk()); } diff --git a/server/src/test/java/server/haengdong/presentation/admin/AdminMemberActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/admin/AdminMemberActionControllerTest.java deleted file mode 100644 index e3d74640d..000000000 --- a/server/src/test/java/server/haengdong/presentation/admin/AdminMemberActionControllerTest.java +++ /dev/null @@ -1,53 +0,0 @@ -package server.haengdong.presentation.admin; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.http.MediaType; -import server.haengdong.presentation.ControllerTestSupport; -import server.haengdong.presentation.request.MemberActionsSaveRequest; - -class AdminMemberActionControllerTest extends ControllerTestSupport { - - @DisplayName("참여자 행동을 추가한다.") - @Test - void saveMemberActionTest() throws Exception { - MemberActionsSaveRequest memberActionsSaveRequest = new MemberActionsSaveRequest( - List.of("웨디", "소하", "토다리", "쿠키"), "IN"); - - String requestBody = objectMapper.writeValueAsString(memberActionsSaveRequest); - - mockMvc.perform(post("/api/admin/events/{eventId}/member-actions", "망쵸토큰") - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) - .andDo(print()) - .andExpect(status().isOk()); - } - - @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") - @Test - void deleteMemberAction() throws Exception { - String eventId = "망쵸토큰"; - Long actionId = 2L; - - mockMvc.perform(delete("/api/admin/events/{eventId}/member-actions/{actionId}", eventId, actionId)) - .andDo(print()) - .andExpect(status().isOk()); - } - - @DisplayName("행사의 전체 참여자 중에서 특정 참여자의 맴버 액션을 전부 삭제한다.") - @Test - void deleteMember() throws Exception { - String eventId = "망쵸토큰"; - String memberName = "행동대장"; - - mockMvc.perform(delete("/api/admin/events/{eventId}/members/{memberName}", eventId, memberName)) - .andDo(print()) - .andExpect(status().isOk()); - } -} diff --git a/server/src/test/java/server/haengdong/presentation/admin/AdminMemberControllerTest.java b/server/src/test/java/server/haengdong/presentation/admin/AdminMemberControllerTest.java new file mode 100644 index 000000000..6afb013f9 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/admin/AdminMemberControllerTest.java @@ -0,0 +1,90 @@ +package server.haengdong.presentation.admin; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import server.haengdong.application.response.MemberSaveAppResponse; +import server.haengdong.application.response.MembersSaveAppResponse; +import server.haengdong.presentation.ControllerTestSupport; +import server.haengdong.presentation.request.MemberSaveRequest; +import server.haengdong.presentation.request.MemberUpdateRequest; +import server.haengdong.presentation.request.MembersSaveRequest; +import server.haengdong.presentation.request.MembersUpdateRequest; + +class AdminMemberControllerTest extends ControllerTestSupport { + + @DisplayName("행사 참여자를 추가한다.") + @Test + void saveMemberTest() throws Exception { + String eventToken = "망쵸토큰"; + MembersSaveRequest membersSaveRequest = new MembersSaveRequest( + List.of( + new MemberSaveRequest("웨디"), + new MemberSaveRequest("소하") + ) + ); + String requestBody = objectMapper.writeValueAsString(membersSaveRequest); + MembersSaveAppResponse appResponse = new MembersSaveAppResponse( + List.of( + new MemberSaveAppResponse(1L, "웨디"), + new MemberSaveAppResponse(2L, "소하") + ) + ); + given(memberService.saveMembers(eventToken, membersSaveRequest.toAppRequest())) + .willReturn(appResponse); + + mockMvc.perform(post("/api/admin/events/{eventId}/members", "망쵸토큰") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.members[0].id").value(equalTo(1))) + .andExpect(MockMvcResultMatchers.jsonPath("$.members[0].name").value(equalTo("웨디"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.members[1].id").value(equalTo(2))) + .andExpect(MockMvcResultMatchers.jsonPath("$.members[1].name").value(equalTo("소하"))); + } + + @DisplayName("행사 참여 인원을 삭제한다.") + @Test + void deleteMember() throws Exception { + String eventId = "망쵸토큰"; + Long memberId = 1L; + + mockMvc.perform(delete("/api/admin/events/{eventId}/members/{memberId}", eventId, memberId)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("행사 참여 인원 정보를 수정한다.") + @Test + void updateMembers() throws Exception { + String eventId = "망쵸토큰"; + MembersUpdateRequest membersUpdateRequest = new MembersUpdateRequest( + List.of( + new MemberUpdateRequest(1L, "토다리", true), + new MemberUpdateRequest(2L, "쿠키", false) + ) + ); + String requestBody = objectMapper.writeValueAsString(membersUpdateRequest); + + mockMvc.perform(put("/api/admin/events/{eventId}/members", eventId) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + .cookie(EVENT_COOKIE) + ) + .andDo(print()) + .andExpect(status().isOk()); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java b/server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java deleted file mode 100644 index 051fcae0f..000000000 --- a/server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java +++ /dev/null @@ -1,63 +0,0 @@ -package server.haengdong.presentation.response; - - -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import server.haengdong.application.response.ActionAppResponse; -import server.haengdong.application.response.ActionAppResponse.ActionType; - -class StepsResponseTest { - - @DisplayName("이웃한 같은 타입의 액션들을 그룹화 하여 응답객체를 생성한다.") - @Test - void of() { - List<ActionAppResponse> actions = List.of( - new ActionAppResponse(1L, "망쵸", null, 1L, ActionType.IN), - new ActionAppResponse(2L, "백호", null, 2L, ActionType.IN), - new ActionAppResponse(3L, "감자탕", 10_000L, 3L, ActionType.BILL), - new ActionAppResponse(4L, "인생네컷", 10_000L, 4L, ActionType.BILL), - new ActionAppResponse(5L, "소하", null, 5L, ActionType.IN), - new ActionAppResponse(6L, "웨디", null, 6L, ActionType.IN), - new ActionAppResponse(7L, "망쵸", null, 7L, ActionType.OUT), - new ActionAppResponse(8L, "백호", null, 8L, ActionType.OUT), - new ActionAppResponse(9L, "노래방", 20_000L, 9L, ActionType.BILL) - ); - - StepsResponse stepsResponse = StepsResponse.of(actions); - - StepsResponse expected = new StepsResponse( - List.of( - new StepResponse("0차", "IN", List.of("망쵸", "백호"), List.of( - new ActionResponse(1L, "망쵸", null, 1L), - new ActionResponse(2L, "백호", null, 2L) - )), - new StepResponse("1차", "BILL", List.of("망쵸", "백호"), List.of( - new ActionResponse(3L, "감자탕", 10_000L, 3L), - new ActionResponse(4L, "인생네컷", 10_000L, 4L) - )), - new StepResponse("1차", "IN", List.of("망쵸", "백호", "소하", "웨디"), List.of( - new ActionResponse(5L, "소하", null, 5L), - new ActionResponse(6L, "웨디", null, 6L) - )), - new StepResponse("1차", "OUT", List.of("소하", "웨디"), List.of( - new ActionResponse(7L, "망쵸", null, 7L), - new ActionResponse(8L, "백호", null, 8L) - )), - new StepResponse("2차", "BILL", List.of("소하", "웨디"), List.of( - new ActionResponse(9L, "노래방", 20_000L, 9L) - )) - ) - ); - assertThat(stepsResponse).isEqualTo(expected); - } - - @DisplayName("액션이 없으면 빈 스탭들이 만들어진다.") - @Test - void ofEmpty() { - StepsResponse stepsResponse = StepsResponse.of(List.of()); - assertThat(stepsResponse.steps()).isEmpty(); - } -} diff --git a/server/src/test/java/server/haengdong/support/fixture/Fixture.java b/server/src/test/java/server/haengdong/support/fixture/Fixture.java index b8d736d4b..e05b43c23 100644 --- a/server/src/test/java/server/haengdong/support/fixture/Fixture.java +++ b/server/src/test/java/server/haengdong/support/fixture/Fixture.java @@ -1,10 +1,8 @@ package server.haengdong.support.fixture; import jakarta.servlet.http.Cookie; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionStatus; -import server.haengdong.domain.action.Sequence; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.member.Member; import server.haengdong.domain.event.Event; public class Fixture { @@ -12,15 +10,9 @@ public class Fixture { public static final Event EVENT1 = new Event("쿠키", "1234", "TOKEN1"); public static final Event EVENT2 = new Event("웨디", "1234", "TOKEN2"); public static final Cookie EVENT_COOKIE = new Cookie("eventToken", "토큰토큰"); - public static final BillAction BILL_ACTION = new BillAction(EVENT1, new Sequence(1L), "뽕족", 30_000L); - - public static BillAction createBillAction(Event event, Long sequence, String title, Long price) { - return new BillAction(event, new Sequence(sequence), title, price); - } - - public static MemberAction createMemberAction( - Event event, Long sequence, String memberName, MemberActionStatus status - ) { - return new MemberAction(event, new Sequence(sequence), memberName, status); - } + public static final Member MEMBER1 = new Member(EVENT1, "토다리"); + public static final Member MEMBER2 = new Member(EVENT1, "쿠키"); + public static final Member MEMBER3 = new Member(EVENT1, "소하"); + public static final Bill BILL1 = new Bill(EVENT1, "행동대장 회식", 10000L); + public static final Bill BILL2 = new Bill(EVENT2, "행동대장 회식2", 20000L); } From bff14b237ebc8fea7dc672faca9b1e04ead40012 Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Thu, 19 Sep 2024 21:28:17 +0900 Subject: [PATCH 170/178] =?UTF-8?q?refactor:=20=EA=B4=80=EB=A6=AC=EC=9E=90?= =?UTF-8?q?=20=EC=9D=B8=EC=A6=9D=20=EB=B6=88=EA=B0=80=20=EB=B2=84=EA=B7=B8?= =?UTF-8?q?=20=EC=88=98=EC=A0=95=20(#572)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 관리자 인증 불가 버그 수정 * test: 테스트 케이스 추가 --- .../haengdong/config/AdminInterceptor.java | 19 ++++++- .../config/AdminInterceptorTest.java | 56 +++++++++++++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 server/src/test/java/server/haengdong/config/AdminInterceptorTest.java diff --git a/server/src/main/java/server/haengdong/config/AdminInterceptor.java b/server/src/main/java/server/haengdong/config/AdminInterceptor.java index 6e13f4c96..acfe99789 100644 --- a/server/src/main/java/server/haengdong/config/AdminInterceptor.java +++ b/server/src/main/java/server/haengdong/config/AdminInterceptor.java @@ -2,6 +2,8 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpMethod; import org.springframework.web.servlet.HandlerInterceptor; @@ -13,6 +15,10 @@ @Slf4j public class AdminInterceptor implements HandlerInterceptor { + private static final String ADMIN_URI_REGEX = "/api/admin/events/([^/]+)"; + private static final Pattern ADMIN_URI_PATTERN = Pattern.compile(ADMIN_URI_REGEX); + private static final int EVENT_TOKEN_MATCHER_INDEX = 1; + private final AuthService authService; private final AuthenticationExtractor authenticationExtractor; @@ -34,9 +40,16 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons private void validateToken(HttpServletRequest request) { String token = authenticationExtractor.extract(request, authService.getTokenName()); String tokenEventId = authService.findEventIdByToken(token); - String eventId = request.getRequestURI().split("/")[3]; - if (!tokenEventId.equals(eventId)) { - log.warn("[행사 접근 불가] Cookie EventId = {}, URL EventId = {}", tokenEventId, eventId); + String uri = request.getRequestURI(); + + Matcher matcher = ADMIN_URI_PATTERN.matcher(uri); + if (!matcher.find()) { + throw new AuthenticationException(HaengdongErrorCode.FORBIDDEN); + } + + String eventToken = matcher.group(EVENT_TOKEN_MATCHER_INDEX); + if (!tokenEventId.equals(eventToken)) { + log.warn("[행사 접근 불가] Cookie EventId = {}, URL EventId = {}", tokenEventId, eventToken); throw new AuthenticationException(HaengdongErrorCode.FORBIDDEN); } } diff --git a/server/src/test/java/server/haengdong/config/AdminInterceptorTest.java b/server/src/test/java/server/haengdong/config/AdminInterceptorTest.java new file mode 100644 index 000000000..f66da7fd1 --- /dev/null +++ b/server/src/test/java/server/haengdong/config/AdminInterceptorTest.java @@ -0,0 +1,56 @@ +package server.haengdong.config; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import server.haengdong.application.AuthService; +import server.haengdong.exception.AuthenticationException; +import server.haengdong.infrastructure.auth.AuthenticationExtractor; + +class AdminInterceptorTest { + + private AuthService authService; + private AuthenticationExtractor authenticationExtractor; + private AdminInterceptor adminInterceptor; + + @BeforeEach + public void setUp() { + authService = mock(AuthService.class); + authenticationExtractor = mock(AuthenticationExtractor.class); + adminInterceptor = new AdminInterceptor(authService, authenticationExtractor); + } + + @DisplayName("쿠키의 JWT 에서 eventToken 과 uri 의 eventToken 이 일치하면 관리자이다.") + @ParameterizedTest + @ValueSource(strings = {"/api/admin/events/12345", "/api/admin/events/12345/bills"}) + void validateToken1(String uri) { + MockHttpServletRequest request = new MockHttpServletRequest("GET", uri); + MockHttpServletResponse response = new MockHttpServletResponse(); + when(authService.findEventIdByToken(any())).thenReturn("12345"); + + boolean preHandle = adminInterceptor.preHandle(request, response, new Object()); + + assertThat(preHandle).isTrue(); + } + + @DisplayName("쿠키의 JWT 에서 eventToken 과 uri 의 eventToken 이 일치하지 않으면 거절당한다.") + @ParameterizedTest + @ValueSource(strings = {"/api/admin/events/12345", "/api/admin/events/12345/bills"}) + void validateToken2(String uri) { + MockHttpServletRequest request = new MockHttpServletRequest("GET", uri); + MockHttpServletResponse response = new MockHttpServletResponse(); + when(authService.findEventIdByToken(any())).thenReturn("125"); + + assertThatThrownBy(() -> adminInterceptor.preHandle(request, response, new Object())) + .isInstanceOf(AuthenticationException.class); + } +} From 5231f2ac812d7ad9eddfa39d21c32d411fdaefb6 Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Mon, 23 Sep 2024 14:17:27 +0900 Subject: [PATCH 171/178] =?UTF-8?q?refactor:=20Domain=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=EC=99=80=20Exception=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=EA=B0=84=EC=9D=98=20=EC=88=9C=ED=99=98=20=EC=B0=B8=EC=A1=B0=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0=20(#581)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: Exception 예외 전달시 순환 참조 문제 해결 * style: 액션 삭제 * refactor: 도메인 매직 넘버 public -> private --- server/src/docs/asciidoc/bill.adoc | 2 +- server/src/docs/asciidoc/billDetail.adoc | 4 +-- .../haengdong/application/EventService.java | 2 +- .../haengdong/application/MemberService.java | 3 +- .../server/haengdong/domain/bill/Bill.java | 12 ++++---- .../{member => bill}/MemberBillReport.java | 5 ++-- .../server/haengdong/domain/event/Bank.java | 4 +-- .../server/haengdong/domain/event/Event.java | 14 +++++---- .../haengdong/domain/event/Password.java | 4 +-- .../haengdong/domain/member/Member.java | 6 ++-- .../haengdong/exception/ErrorResponse.java | 6 ++-- .../exception/GlobalExceptionHandler.java | 2 +- .../exception/HaengdongErrorCode.java | 30 +++++-------------- .../exception/HaengdongException.java | 8 ++--- .../application/MemberServiceTest.java | 2 +- .../docs/BillControllerDocsTest.java | 2 +- .../domain/member/MemberBillReportTest.java | 1 + .../presentation/BillControllerTest.java | 2 +- .../admin/AdminBillControllerTest.java | 16 +++++----- 19 files changed, 56 insertions(+), 69 deletions(-) rename server/src/main/java/server/haengdong/domain/{member => bill}/MemberBillReport.java (84%) diff --git a/server/src/docs/asciidoc/bill.adoc b/server/src/docs/asciidoc/bill.adoc index db77542aa..64b366594 100644 --- a/server/src/docs/asciidoc/bill.adoc +++ b/server/src/docs/asciidoc/bill.adoc @@ -75,7 +75,7 @@ operation::updateBill[snippets="path-parameters,http-request,request-body,reques }, { "code":"BILL_NOT_FOUND", - "message":"존재하지 않는 지출 액션입니다." + "message":"존재하지 않는 지출입니다." }, { "code":"TOKEN_NOT_FOUND", diff --git a/server/src/docs/asciidoc/billDetail.adoc b/server/src/docs/asciidoc/billDetail.adoc index 9c9cf7ff5..349fb309c 100644 --- a/server/src/docs/asciidoc/billDetail.adoc +++ b/server/src/docs/asciidoc/billDetail.adoc @@ -15,7 +15,7 @@ operation::findBillDetails[snippets="path-parameters,http-request,http-response, }, { "code": "BILL_NOT_FOUND", - "message": "존재하지 않는 지출 액션입니다." + "message": "존재하지 않는 지출입니다." }, { "code": "BILL_DETAIL_NOT_FOUND", @@ -63,7 +63,7 @@ operation::updateBillDetails[snippets="path-parameters,http-request,request-body }, { "code": "BILL_NOT_FOUND", - "message": "존재하지 않는 지출 액션입니다." + "message": "존재하지 않는 지출 입니다." }, { "code": "BILL_DETAIL_NOT_FOUND", diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java index bb6d2b51f..af49ebb5a 100644 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -14,7 +14,7 @@ import server.haengdong.domain.bill.Bill; import server.haengdong.domain.bill.BillRepository; import server.haengdong.domain.member.Member; -import server.haengdong.domain.member.MemberBillReport; +import server.haengdong.domain.bill.MemberBillReport; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.domain.event.EventTokenProvider; diff --git a/server/src/main/java/server/haengdong/application/MemberService.java b/server/src/main/java/server/haengdong/application/MemberService.java index d54d3b3a0..765f4eacf 100644 --- a/server/src/main/java/server/haengdong/application/MemberService.java +++ b/server/src/main/java/server/haengdong/application/MemberService.java @@ -63,8 +63,7 @@ public List<MemberAppResponse> getCurrentMembers(String token) { private void validateMemberSave(List<String> memberNames, Event event) { if (memberNamesDuplicated(memberNames)) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE, - "중복된 이름이 존재합니다. 입력된 이름: " + memberNames); + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE, memberNames); } if (memberRepository.findAllByEvent(event).stream() .anyMatch(member -> memberNames.contains(member.getName()))) { diff --git a/server/src/main/java/server/haengdong/domain/bill/Bill.java b/server/src/main/java/server/haengdong/domain/bill/Bill.java index 10043bbcf..69be84523 100644 --- a/server/src/main/java/server/haengdong/domain/bill/Bill.java +++ b/server/src/main/java/server/haengdong/domain/bill/Bill.java @@ -29,10 +29,10 @@ @Entity public class Bill { - public static final int MIN_TITLE_LENGTH = 1; - public static final int MAX_TITLE_LENGTH = 30; - public static final long MIN_PRICE = 1L; - public static final long MAX_PRICE = 10_000_000L; + private static final int MIN_TITLE_LENGTH = 1; + private static final int MAX_TITLE_LENGTH = 30; + private static final long MIN_PRICE = 1L; + private static final long MAX_PRICE = 10_000_000L; private static final long DEFAULT_PRICE = 0L; @Id @@ -63,13 +63,13 @@ public Bill(Event event, String title, Long price) { private void validateTitle(String title) { int titleLength = title.trim().length(); if (titleLength < MIN_TITLE_LENGTH || titleLength > MAX_TITLE_LENGTH) { - throw new HaengdongException(HaengdongErrorCode.BILL_TITLE_INVALID); + throw new HaengdongException(HaengdongErrorCode.BILL_TITLE_INVALID, MIN_TITLE_LENGTH, MAX_TITLE_LENGTH); } } private void validatePrice(Long price) { if (price < MIN_PRICE || price > MAX_PRICE) { - throw new HaengdongException(HaengdongErrorCode.BILL_PRICE_INVALID); + throw new HaengdongException(HaengdongErrorCode.BILL_PRICE_INVALID, MAX_PRICE); } } diff --git a/server/src/main/java/server/haengdong/domain/member/MemberBillReport.java b/server/src/main/java/server/haengdong/domain/bill/MemberBillReport.java similarity index 84% rename from server/src/main/java/server/haengdong/domain/member/MemberBillReport.java rename to server/src/main/java/server/haengdong/domain/bill/MemberBillReport.java index 25a7d165d..ee16824d0 100644 --- a/server/src/main/java/server/haengdong/domain/member/MemberBillReport.java +++ b/server/src/main/java/server/haengdong/domain/bill/MemberBillReport.java @@ -1,12 +1,11 @@ -package server.haengdong.domain.member; +package server.haengdong.domain.bill; import static java.util.stream.Collectors.toMap; import java.util.List; import java.util.Map; import lombok.Getter; -import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.bill.BillDetail; +import server.haengdong.domain.member.Member; @Getter public class MemberBillReport { diff --git a/server/src/main/java/server/haengdong/domain/event/Bank.java b/server/src/main/java/server/haengdong/domain/event/Bank.java index cac1fdc7c..6e449ae7e 100644 --- a/server/src/main/java/server/haengdong/domain/event/Bank.java +++ b/server/src/main/java/server/haengdong/domain/event/Bank.java @@ -40,10 +40,10 @@ public static void isExists(String bankName) { Arrays.stream(Bank.values()) .filter(bank -> bank.name.equals(bankName)) .findFirst() - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BANK_NAME_INVALID)); + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BANK_NAME_INVALID, getSupportedBanks())); } - public static String getSupportedBanks() { + private static String getSupportedBanks() { return Arrays.stream(Bank.values()) .map(Bank::getName) .reduce((bank1, bank2) -> bank1 + ", " + bank2) diff --git a/server/src/main/java/server/haengdong/domain/event/Event.java b/server/src/main/java/server/haengdong/domain/event/Event.java index fcbeaab9c..30dd2a8a4 100644 --- a/server/src/main/java/server/haengdong/domain/event/Event.java +++ b/server/src/main/java/server/haengdong/domain/event/Event.java @@ -18,10 +18,10 @@ @Entity public class Event { - public static final int MIN_NAME_LENGTH = 1; - public static final int MAX_NAME_LENGTH = 20; - public static final int MIN_ACCOUNT_NUMBER_LENGTH = 8; - public static final int MAX_ACCOUNT_NUMBER_LENGTH = 30; + private static final int MIN_NAME_LENGTH = 1; + private static final int MAX_NAME_LENGTH = 20; + private static final int MIN_ACCOUNT_NUMBER_LENGTH = 8; + private static final int MAX_ACCOUNT_NUMBER_LENGTH = 30; private static final String SPACES = " "; @Id @@ -53,7 +53,8 @@ public Event(String name, String password, String token) { private void validateName(String name) { int nameLength = name.trim().length(); if (nameLength < MIN_NAME_LENGTH || MAX_NAME_LENGTH < nameLength) { - throw new HaengdongException(HaengdongErrorCode.EVENT_NAME_LENGTH_INVALID); + throw new HaengdongException( + HaengdongErrorCode.EVENT_NAME_LENGTH_INVALID, MIN_NAME_LENGTH, MAX_NAME_LENGTH); } if (isBlankContinuous(name)) { throw new HaengdongException(HaengdongErrorCode.EVENT_NAME_CONSECUTIVE_SPACES); @@ -90,7 +91,8 @@ private void validateBankName(String bankName) { private void validateAccountNumber(String accountNumber) { int accountLength = accountNumber.trim().length(); if (accountLength < MIN_ACCOUNT_NUMBER_LENGTH || MAX_ACCOUNT_NUMBER_LENGTH < accountLength) { - throw new HaengdongException(HaengdongErrorCode.ACCOUNT_LENGTH_INVALID); + throw new HaengdongException( + HaengdongErrorCode.ACCOUNT_LENGTH_INVALID, MIN_ACCOUNT_NUMBER_LENGTH, MAX_ACCOUNT_NUMBER_LENGTH); } } } diff --git a/server/src/main/java/server/haengdong/domain/event/Password.java b/server/src/main/java/server/haengdong/domain/event/Password.java index 375849dbf..7c195b5d5 100644 --- a/server/src/main/java/server/haengdong/domain/event/Password.java +++ b/server/src/main/java/server/haengdong/domain/event/Password.java @@ -17,7 +17,7 @@ @Embeddable public class Password { - public static final int PASSWORD_LENGTH = 4; + private static final int PASSWORD_LENGTH = 4; private static final Pattern PASSWORD_PATTERN = Pattern.compile(String.format("^\\d{%d}$", PASSWORD_LENGTH)); private static final String HASH_ALGORITHM = "SHA-256"; @@ -31,7 +31,7 @@ public Password(String password) { private void validatePassword(String password) { Matcher matcher = PASSWORD_PATTERN.matcher(password); if (!matcher.matches()) { - throw new HaengdongException(HaengdongErrorCode.EVENT_PASSWORD_FORMAT_INVALID); + throw new HaengdongException(HaengdongErrorCode.EVENT_PASSWORD_FORMAT_INVALID, PASSWORD_LENGTH); } } diff --git a/server/src/main/java/server/haengdong/domain/member/Member.java b/server/src/main/java/server/haengdong/domain/member/Member.java index d569915e1..7180d57e4 100644 --- a/server/src/main/java/server/haengdong/domain/member/Member.java +++ b/server/src/main/java/server/haengdong/domain/member/Member.java @@ -24,8 +24,8 @@ @Entity public class Member { - public static final int MIN_NAME_LENGTH = 1; - public static final int MAX_NAME_LENGTH = 8; + private static final int MIN_NAME_LENGTH = 1; + private static final int MAX_NAME_LENGTH = 8; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -56,7 +56,7 @@ public Member(Long id, Event event, String name, boolean isDeposited) { private void validateName(String name) { int nameLength = name.length(); if (nameLength < MIN_NAME_LENGTH || nameLength > MAX_NAME_LENGTH) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_LENGTH_INVALID); + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_LENGTH_INVALID, MIN_NAME_LENGTH, MAX_NAME_LENGTH); } } diff --git a/server/src/main/java/server/haengdong/exception/ErrorResponse.java b/server/src/main/java/server/haengdong/exception/ErrorResponse.java index d0a2b01a0..3937f4322 100644 --- a/server/src/main/java/server/haengdong/exception/ErrorResponse.java +++ b/server/src/main/java/server/haengdong/exception/ErrorResponse.java @@ -1,15 +1,15 @@ package server.haengdong.exception; public record ErrorResponse( - HaengdongErrorCode errorCode, + String errorCode, String message ) { public static ErrorResponse of(HaengdongErrorCode errorCode) { - return new ErrorResponse(errorCode, errorCode.getMessage()); + return new ErrorResponse(errorCode.name(), errorCode.getMessage()); } public static ErrorResponse of(HaengdongErrorCode errorCode, String message) { - return new ErrorResponse(errorCode, message); + return new ErrorResponse(errorCode.name(), message); } } diff --git a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java index 0cee7cb4c..4d2c96c73 100644 --- a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java +++ b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java @@ -69,7 +69,7 @@ public ResponseEntity<ErrorResponse> handleMethodArgumentNotValidException(Metho public ResponseEntity<ErrorResponse> haengdongException(HttpServletRequest req, HaengdongException e) { log.warn(LOG_FORMAT, req.getMethod(), req.getRequestURI(), getRequestBody(req), e.getMessage(), e); return ResponseEntity.badRequest() - .body(ErrorResponse.of(e.getErrorCode())); + .body(ErrorResponse.of(e.getErrorCode(), e.getMessage())); } @ExceptionHandler(Exception.class) diff --git a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java index e320a77d4..7030c4907 100644 --- a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java +++ b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java @@ -1,11 +1,6 @@ package server.haengdong.exception; import lombok.Getter; -import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.member.Member; -import server.haengdong.domain.event.Bank; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.Password; @Getter public enum HaengdongErrorCode { @@ -13,30 +8,21 @@ public enum HaengdongErrorCode { /* Domain */ EVENT_NOT_FOUND("존재하지 않는 행사입니다."), - EVENT_NAME_LENGTH_INVALID(String.format("행사 이름은 %d자 이상 %d자 이하만 입력 가능합니다.", - Event.MIN_NAME_LENGTH, - Event.MAX_NAME_LENGTH)), + EVENT_NAME_LENGTH_INVALID("행사 이름은 %d자 이상 %d자 이하만 입력 가능합니다."), EVENT_NAME_CONSECUTIVE_SPACES("행사 이름에는 공백 문자가 연속될 수 없습니다."), - EVENT_PASSWORD_FORMAT_INVALID(String.format("비밀번호는 %d자리 숫자만 가능합니다.", Password.PASSWORD_LENGTH)), - BANK_NAME_INVALID(String.format("지원하지 않는 은행입니다. 지원하는 은행 목록: %s", - Bank.getSupportedBanks())), - ACCOUNT_LENGTH_INVALID(String.format("계좌번호는 %d자 이상 %d자 이하만 입력 가능합니다.", - Event.MIN_ACCOUNT_NUMBER_LENGTH, - Event.MAX_ACCOUNT_NUMBER_LENGTH)), - - MEMBER_NAME_LENGTH_INVALID(String.format("멤버 이름은 %d자 이상 %d자 이하만 입력 가능합니다.", - Member.MIN_NAME_LENGTH, - Member.MAX_NAME_LENGTH)), + EVENT_PASSWORD_FORMAT_INVALID("비밀번호는 %d자리 숫자만 가능합니다."), + BANK_NAME_INVALID("지원하지 않는 은행입니다. 지원하는 은행 목록: %s"), + ACCOUNT_LENGTH_INVALID("계좌번호는 %d자 이상 %d자 이하만 입력 가능합니다."), + + MEMBER_NAME_LENGTH_INVALID("멤버 이름은 %d자 이상 %d자 이하만 입력 가능합니다."), MEMBER_NAME_DUPLICATE("중복된 행사 참여 인원 이름이 존재합니다."), MEMBER_NOT_FOUND("존재하지 않는 참여자입니다."), MEMBER_ALREADY_EXIST("현재 참여하고 있는 인원이 존재합니다."), MEMBER_NAME_CHANGE_DUPLICATE("중복된 참여 인원 이름 변경 요청이 존재합니다."), BILL_NOT_FOUND("존재하지 않는 지출입니다."), - BILL_TITLE_INVALID(String.format("앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다.", - Bill.MIN_TITLE_LENGTH, - Bill.MAX_TITLE_LENGTH)), - BILL_PRICE_INVALID(String.format("지출 금액은 %,d 이하의 자연수여야 합니다.", Bill.MAX_PRICE)), + BILL_TITLE_INVALID("앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다."), + BILL_PRICE_INVALID("지출 금액은 %,d 이하의 자연수여야 합니다."), BILL_DETAIL_NOT_FOUND("존재하지 않는 참여자 지출입니다."), BILL_PRICE_NOT_MATCHED("지출 총액이 일치하지 않습니다."), diff --git a/server/src/main/java/server/haengdong/exception/HaengdongException.java b/server/src/main/java/server/haengdong/exception/HaengdongException.java index b86fe4ffc..4454fe7bf 100644 --- a/server/src/main/java/server/haengdong/exception/HaengdongException.java +++ b/server/src/main/java/server/haengdong/exception/HaengdongException.java @@ -6,14 +6,14 @@ public class HaengdongException extends RuntimeException { private final HaengdongErrorCode errorCode; - private final String message; public HaengdongException(HaengdongErrorCode errorCode) { - this(errorCode, errorCode.getMessage()); + super(errorCode.getMessage()); + this.errorCode = errorCode; } - public HaengdongException(HaengdongErrorCode errorCode, String message) { + public HaengdongException(HaengdongErrorCode errorCode, Object... args) { + super(String.format(errorCode.getMessage(), args)); this.errorCode = errorCode; - this.message = message; } } diff --git a/server/src/test/java/server/haengdong/application/MemberServiceTest.java b/server/src/test/java/server/haengdong/application/MemberServiceTest.java index 88709eb29..62bb7a0b8 100644 --- a/server/src/test/java/server/haengdong/application/MemberServiceTest.java +++ b/server/src/test/java/server/haengdong/application/MemberServiceTest.java @@ -119,7 +119,7 @@ void saveMembersTest2() { assertThatThrownBy(() -> memberService.saveMembers(event.getToken(), request)) .isInstanceOf(HaengdongException.class) - .hasMessageContaining("중복된 이름이 존재합니다. 입력된 이름: [토다리, 토다리]"); + .hasMessageContaining("중복된 행사 참여 인원 이름이 존재합니다."); } @DisplayName("행사 참여 인원을 삭제한다.") diff --git a/server/src/test/java/server/haengdong/docs/BillControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/BillControllerDocsTest.java index f960d6195..0716a2123 100644 --- a/server/src/test/java/server/haengdong/docs/BillControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/BillControllerDocsTest.java @@ -88,7 +88,7 @@ void findBills() throws Exception { @DisplayName("참여자별 지출 금액을 조회한다.") @Test - void findBillActionDetails() throws Exception { + void findBillDetails() throws Exception { BillDetailsAppResponse appResponse = new BillDetailsAppResponse( List.of(new BillDetailAppResponse(1L, "토다리", 1000L, false))); given(billService.findBillDetails(anyString(), anyLong())).willReturn(appResponse); diff --git a/server/src/test/java/server/haengdong/domain/member/MemberBillReportTest.java b/server/src/test/java/server/haengdong/domain/member/MemberBillReportTest.java index ca33603a1..187d117f7 100644 --- a/server/src/test/java/server/haengdong/domain/member/MemberBillReportTest.java +++ b/server/src/test/java/server/haengdong/domain/member/MemberBillReportTest.java @@ -8,6 +8,7 @@ import org.junit.jupiter.api.Test; import server.haengdong.domain.bill.Bill; import server.haengdong.domain.event.Event; +import server.haengdong.domain.bill.MemberBillReport; import server.haengdong.support.fixture.Fixture; class MemberBillReportTest { diff --git a/server/src/test/java/server/haengdong/presentation/BillControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillControllerTest.java index 10d7fd1f6..b6658d7b6 100644 --- a/server/src/test/java/server/haengdong/presentation/BillControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/BillControllerTest.java @@ -50,7 +50,7 @@ void findBills() throws Exception { @DisplayName("참여자별 지출 금액을 조회한다.") @Test - void findBillActionDetails() throws Exception { + void findBillDetails() throws Exception { BillDetailsAppResponse appResponse = new BillDetailsAppResponse( List.of(new BillDetailAppResponse(1L, "토다리", 1000L, false))); given(billService.findBillDetails(anyString(), anyLong())).willReturn(appResponse); diff --git a/server/src/test/java/server/haengdong/presentation/admin/AdminBillControllerTest.java b/server/src/test/java/server/haengdong/presentation/admin/AdminBillControllerTest.java index f776a1624..e3599a9ee 100644 --- a/server/src/test/java/server/haengdong/presentation/admin/AdminBillControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/admin/AdminBillControllerTest.java @@ -26,7 +26,7 @@ class AdminBillControllerTest extends ControllerTestSupport { @DisplayName("지출 내역을 생성한다.") @Test - void saveAllBillAction() throws Exception { + void saveAllBill() throws Exception { List<Long> members = List.of(1L, 2L); BillSaveRequest request = new BillSaveRequest("뽕족", 10_000L, members); @@ -43,7 +43,7 @@ void saveAllBillAction() throws Exception { @DisplayName("title이 비어 있는 경우 지출 내역을 생성할 수 없다.") @Test - void saveAllBillAction1() throws Exception { + void saveAllBill1() throws Exception { List<Long> members = List.of(1L, 2L); BillSaveRequest request = new BillSaveRequest("", 10_000L, members); @@ -59,7 +59,7 @@ void saveAllBillAction1() throws Exception { @DisplayName("지출 액션을 수정한다.") @Test - void updateBillAction() throws Exception { + void updateBill() throws Exception { BillUpdateRequest request = new BillUpdateRequest("뽕족", 10_000L); String requestBody = objectMapper.writeValueAsString(request); @@ -75,7 +75,7 @@ void updateBillAction() throws Exception { @DisplayName("지출 내역을 삭제한다.") @Test - void deleteBillAction() throws Exception { + void deleteBill() throws Exception { String eventId = "토다리토큰"; mockMvc.perform(delete("/api/admin/events/{eventId}/bills/{billId}", eventId, 1)) @@ -85,7 +85,7 @@ void deleteBillAction() throws Exception { @DisplayName("존재하지 않는 행사에 대한 지출 내역을 삭제할 수 없다.") @Test - void deleteBillAction1() throws Exception { + void deleteBill1() throws Exception { String eventId = "이상해토큰"; doThrow(new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)) .when(billService).deleteBill(any(String.class), any(Long.class)); @@ -97,13 +97,13 @@ void deleteBillAction1() throws Exception { @DisplayName("참여자별 지출 금액을 수정한다.") @Test - void updateBillActionDetailsTest() throws Exception { - List<BillDetailUpdateRequest> billActionDetailUpdateRequests = List.of( + void updateBillDetailsTest() throws Exception { + List<BillDetailUpdateRequest> billDetailUpdateRequests = List.of( new BillDetailUpdateRequest(1L, 10000L, true), new BillDetailUpdateRequest(2L, 20000L, true) ); BillDetailsUpdateRequest request = new BillDetailsUpdateRequest( - billActionDetailUpdateRequests); + billDetailUpdateRequests); String json = objectMapper.writeValueAsString(request); From 243cd0d49ac30a485fa6ada01246152c69e40ef9 Mon Sep 17 00:00:00 2001 From: juha <84626225+khabh@users.noreply.github.com> Date: Mon, 23 Sep 2024 15:13:17 +0900 Subject: [PATCH 172/178] =?UTF-8?q?fix:=20Transactional=20write=20?= =?UTF-8?q?=EA=B0=80=EB=8A=A5=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20(#589)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/server/haengdong/application/MemberService.java | 5 +++-- .../server/haengdong/application/ServiceTestSupport.java | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/MemberService.java b/server/src/main/java/server/haengdong/application/MemberService.java index 765f4eacf..7b439ada0 100644 --- a/server/src/main/java/server/haengdong/application/MemberService.java +++ b/server/src/main/java/server/haengdong/application/MemberService.java @@ -17,10 +17,10 @@ import server.haengdong.domain.bill.Bill; import server.haengdong.domain.bill.BillDetailRepository; import server.haengdong.domain.bill.BillRepository; -import server.haengdong.domain.member.Member; -import server.haengdong.domain.member.MemberRepository; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; +import server.haengdong.domain.member.Member; +import server.haengdong.domain.member.MemberRepository; import server.haengdong.exception.HaengdongErrorCode; import server.haengdong.exception.HaengdongException; @@ -34,6 +34,7 @@ public class MemberService { private final BillRepository billRepository; private final BillDetailRepository billDetailRepository; + @Transactional public MembersSaveAppResponse saveMembers(String token, MembersSaveAppRequest request) { Event event = getEvent(token); List<String> memberNames = request.members().stream() diff --git a/server/src/test/java/server/haengdong/application/ServiceTestSupport.java b/server/src/test/java/server/haengdong/application/ServiceTestSupport.java index b0e2db0a6..008ba1035 100644 --- a/server/src/test/java/server/haengdong/application/ServiceTestSupport.java +++ b/server/src/test/java/server/haengdong/application/ServiceTestSupport.java @@ -6,6 +6,6 @@ import server.haengdong.support.extension.DatabaseCleanerExtension; @ExtendWith(DatabaseCleanerExtension.class) -@SpringBootTest(webEnvironment= WebEnvironment.NONE) +@SpringBootTest(webEnvironment = WebEnvironment.NONE) abstract class ServiceTestSupport { } From 0290f46cca270c964a085ab0658b7d5e6ead72b1 Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Tue, 24 Sep 2024 13:13:10 +0900 Subject: [PATCH 173/178] =?UTF-8?q?feat:=20=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=EB=B2=A0=EC=9D=B4=EC=8A=A4=20Replication=20=EA=B5=AC=EC=84=B1?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=A5=B8=20Read=20/=20Write=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=ED=95=98=EA=B8=B0=20(#592)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: DataSource 연결 안됨. * feat: prod 환경에 Read, Write Datasource 구분하여 연결 * feat: prod 환경에 Read, Write Datasource 구분하여 연결 * fix: rds 연결 불가 버그 수정 * feat: 서버 증가로 인한 CD 수정 --------- Co-authored-by: Arachneee <jhg2819@naver.com> --- .github/workflows/backend-dev.yml | 38 ++++++++++ server/build.gradle | 1 + .../infrastructure/DataSourceConfig.java | 70 +++++++++++++++++++ .../DynamicRoutingDataSource.java | 18 +++++ server/src/main/resources/config | 2 +- 5 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 server/src/main/java/server/haengdong/infrastructure/DataSourceConfig.java create mode 100644 server/src/main/java/server/haengdong/infrastructure/DynamicRoutingDataSource.java diff --git a/.github/workflows/backend-dev.yml b/.github/workflows/backend-dev.yml index a3257f028..d41e8468f 100644 --- a/.github/workflows/backend-dev.yml +++ b/.github/workflows/backend-dev.yml @@ -70,3 +70,41 @@ jobs: - name: Docker run run: sudo docker run -d -p 8080:8080 -e SPRING_PROFILES_ACTIVE=dev -v log-volume:/app/logs --name haengdong-backend ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }} + + deploy-prod-1: + needs: build + runs-on: [ self-hosted, backend-prod-1 ] + steps: + - name: Docker remove + run: | + CONTAINER_IDS=$(sudo docker ps -qa) + if [ -n "$CONTAINER_IDS" ]; then + sudo docker rm -f $CONTAINER_IDS + else + echo "No running containers found." + fi + + - name: Docker Image pull + run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }} + + - name: Docker run + run: sudo docker run -d -p 80:8080 -e SPRING_PROFILES_ACTIVE=prod -v log-volume:/app/logs --name haengdong-backend ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }} + + deploy-prod-2: + needs: build + runs-on: [ self-hosted, backend-prod-2 ] + steps: + - name: Docker remove + run: | + CONTAINER_IDS=$(sudo docker ps -qa) + if [ -n "$CONTAINER_IDS" ]; then + sudo docker rm -f $CONTAINER_IDS + else + echo "No running containers found." + fi + + - name: Docker Image pull + run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }} + + - name: Docker run + run: sudo docker run -d -p 80:8080 -e SPRING_PROFILES_ACTIVE=prod -v log-volume:/app/logs --name haengdong-backend ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }} diff --git a/server/build.gradle b/server/build.gradle index 4229de130..c2936590a 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -36,6 +36,7 @@ dependencies { compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' + annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor' runtimeOnly 'com.h2database:h2' runtimeOnly 'com.mysql:mysql-connector-j' diff --git a/server/src/main/java/server/haengdong/infrastructure/DataSourceConfig.java b/server/src/main/java/server/haengdong/infrastructure/DataSourceConfig.java new file mode 100644 index 000000000..c859217b4 --- /dev/null +++ b/server/src/main/java/server/haengdong/infrastructure/DataSourceConfig.java @@ -0,0 +1,70 @@ +package server.haengdong.infrastructure; + +import com.zaxxer.hikari.HikariDataSource; +import jakarta.persistence.EntityManagerFactory; +import java.util.HashMap; +import java.util.Map; +import javax.sql.DataSource; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Profile; +import org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.transaction.PlatformTransactionManager; + +@Profile("prod") +@Configuration +public class DataSourceConfig { + + private static final String PRIMARY = "primary"; + private static final String SECONDARY = "secondary"; + + @ConfigurationProperties(prefix = "spring.datasource.hikari.primary") + @Bean + public DataSource primaryDataSource() { + return DataSourceBuilder.create().type(HikariDataSource.class).build(); + } + + @ConfigurationProperties(prefix = "spring.datasource.hikari.secondary") + @Bean + public DataSource secondaryDataSource() { + return DataSourceBuilder.create().type(HikariDataSource.class).build(); + } + + @DependsOn({"primaryDataSource", "secondaryDataSource"}) + @Bean + public DataSource routingDataSource( + @Qualifier("primaryDataSource") DataSource primary, + @Qualifier("secondaryDataSource") DataSource secondary) { + DynamicRoutingDataSource routingDataSource = new DynamicRoutingDataSource(); + + Map<Object, Object> dataSourceMap = new HashMap<>(); + + dataSourceMap.put(PRIMARY, primary); + dataSourceMap.put(SECONDARY, secondary); + + routingDataSource.setTargetDataSources(dataSourceMap); + routingDataSource.setDefaultTargetDataSource(primary); + + return routingDataSource; + } + + @DependsOn({"routingDataSource"}) + @Primary + @Bean + public DataSource dataSource(DataSource routingDataSource) { + return new LazyConnectionDataSourceProxy(routingDataSource); + } + + @Bean + public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { + JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(); + jpaTransactionManager.setEntityManagerFactory(entityManagerFactory); + return jpaTransactionManager; + } +} diff --git a/server/src/main/java/server/haengdong/infrastructure/DynamicRoutingDataSource.java b/server/src/main/java/server/haengdong/infrastructure/DynamicRoutingDataSource.java new file mode 100644 index 000000000..5f84010a1 --- /dev/null +++ b/server/src/main/java/server/haengdong/infrastructure/DynamicRoutingDataSource.java @@ -0,0 +1,18 @@ +package server.haengdong.infrastructure; + +import static org.springframework.transaction.support.TransactionSynchronizationManager.isCurrentTransactionReadOnly; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; + +@Slf4j +public class DynamicRoutingDataSource extends AbstractRoutingDataSource { + + private static final String PRIMARY = "primary"; + private static final String SECONDARY = "secondary"; + + @Override + protected Object determineCurrentLookupKey() { + return isCurrentTransactionReadOnly() ? SECONDARY : PRIMARY; + } +} diff --git a/server/src/main/resources/config b/server/src/main/resources/config index fa4270674..0650f4e19 160000 --- a/server/src/main/resources/config +++ b/server/src/main/resources/config @@ -1 +1 @@ -Subproject commit fa42706743e6eb3f4fd8c34618614eff8ae94b3d +Subproject commit 0650f4e19e85907eeca5a5c16b8cbd7e146f43ab From e0b50800cd5310dc4ee586e38d239389ee9ee76c Mon Sep 17 00:00:00 2001 From: Juhwan Kim <13selfesteem91@naver.com> Date: Tue, 24 Sep 2024 21:59:11 +0900 Subject: [PATCH 174/178] =?UTF-8?q?fix:=20event=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=8B=9C,=20=EC=9D=80=ED=96=89=20=EC=9D=B4=EB=A6=84=EA=B3=BC?= =?UTF-8?q?=20=EA=B3=84=EC=A2=8C=20=EB=B2=88=ED=98=B8=EA=B0=80=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=EB=90=98=EC=96=B4=20=EB=B0=98=ED=99=98=20(#608)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../response/EventDetailAppResponse.java | 5 +-- .../server/haengdong/domain/event/Event.java | 19 ++++++++++- .../response/EventDetailResponse.java | 5 +-- .../application/EventServiceTest.java | 12 ++++--- .../docs/EventControllerDocsTest.java | 5 +-- .../haengdong/domain/event/EventTest.java | 32 ++++++++++++++++++- .../presentation/EventControllerTest.java | 2 +- 7 files changed, 67 insertions(+), 13 deletions(-) diff --git a/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java b/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java index 53fd0b48c..899ea76ec 100644 --- a/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java +++ b/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java @@ -4,10 +4,11 @@ public record EventDetailAppResponse( String eventName, - String account + String bankName, + String accountNumber ) { public static EventDetailAppResponse of(Event event) { - return new EventDetailAppResponse(event.getName(), event.getAccount()); + return new EventDetailAppResponse(event.getName(), event.getBankName(), event.getAccountNumber()); } } diff --git a/server/src/main/java/server/haengdong/domain/event/Event.java b/server/src/main/java/server/haengdong/domain/event/Event.java index 30dd2a8a4..58d080a43 100644 --- a/server/src/main/java/server/haengdong/domain/event/Event.java +++ b/server/src/main/java/server/haengdong/domain/event/Event.java @@ -7,6 +7,7 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import java.util.Arrays; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -92,7 +93,23 @@ private void validateAccountNumber(String accountNumber) { int accountLength = accountNumber.trim().length(); if (accountLength < MIN_ACCOUNT_NUMBER_LENGTH || MAX_ACCOUNT_NUMBER_LENGTH < accountLength) { throw new HaengdongException( - HaengdongErrorCode.ACCOUNT_LENGTH_INVALID, MIN_ACCOUNT_NUMBER_LENGTH, MAX_ACCOUNT_NUMBER_LENGTH); + HaengdongErrorCode.ACCOUNT_LENGTH_INVALID, MIN_ACCOUNT_NUMBER_LENGTH, MAX_ACCOUNT_NUMBER_LENGTH); } } + + public String getBankName() { + String[] bankNameAndAccountNumber = account.split(" "); + if (bankNameAndAccountNumber.length > 0) { + return bankNameAndAccountNumber[0]; + } + return ""; + } + + public String getAccountNumber() { + String[] bankNameAndAccountNumber = account.split(" "); + if (bankNameAndAccountNumber.length > 1) { + return String.join(" ", Arrays.copyOfRange(bankNameAndAccountNumber, 1, bankNameAndAccountNumber.length)); + } + return ""; + } } diff --git a/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java b/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java index c03ae8178..e5421940c 100644 --- a/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java +++ b/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java @@ -4,10 +4,11 @@ public record EventDetailResponse( String eventName, - String account + String bankName, + String accountNumber ) { public static EventDetailResponse of(EventDetailAppResponse response) { - return new EventDetailResponse(response.eventName(), response.account()); + return new EventDetailResponse(response.eventName(), response.bankName(), response.accountNumber()); } } diff --git a/server/src/test/java/server/haengdong/application/EventServiceTest.java b/server/src/test/java/server/haengdong/application/EventServiceTest.java index e5fef4184..e40a682dc 100644 --- a/server/src/test/java/server/haengdong/application/EventServiceTest.java +++ b/server/src/test/java/server/haengdong/application/EventServiceTest.java @@ -76,7 +76,8 @@ void updateEventTest() { Event updateEvent = eventRepository.findByToken(event.getToken()).get(); assertAll( () -> assertThat(updateEvent.getName()).isEqualTo("새로운 행사 이름"), - () -> assertThat(updateEvent.getAccount()).isEqualTo("토스뱅크 12345678") + () -> assertThat(updateEvent.getBankName()).isEqualTo("토스뱅크"), + () -> assertThat(updateEvent.getAccountNumber()).isEqualTo("12345678") ); } @@ -92,7 +93,8 @@ void updateEventTest1() { Event updateEvent = eventRepository.findByToken(event.getToken()).get(); assertAll( () -> assertThat(updateEvent.getName()).isEqualTo("행동대장 비대위"), - () -> assertThat(updateEvent.getAccount()).isEqualTo("토스뱅크 12345678") + () -> assertThat(updateEvent.getBankName()).isEqualTo("토스뱅크"), + () -> assertThat(updateEvent.getAccountNumber()).isEqualTo("12345678") ); } @@ -108,7 +110,8 @@ void updateEventTest2() { Event updateEvent = eventRepository.findByToken(event.getToken()).get(); assertAll( () -> assertThat(updateEvent.getName()).isEqualTo("행동대장 정상 영업"), - () -> assertThat(updateEvent.getAccount()).isEqualTo("") + () -> assertThat(updateEvent.getBankName()).isEqualTo(""), + () -> assertThat(updateEvent.getAccountNumber()).isEqualTo("") ); } @@ -124,7 +127,8 @@ void updateEventTest3() { Event updateEvent = eventRepository.findByToken(event.getToken()).get(); assertAll( () -> assertThat(updateEvent.getName()).isEqualTo("행동대장 비대위"), - () -> assertThat(updateEvent.getAccount()).isEqualTo("") + () -> assertThat(updateEvent.getBankName()).isEqualTo(""), + () -> assertThat(updateEvent.getAccountNumber()).isEqualTo("") ); } diff --git a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java index 36a752953..83144f135 100644 --- a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java @@ -57,7 +57,7 @@ protected Object initController() { @Test void findEventTest() throws Exception { String eventId = "망쵸토큰"; - EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식", "토스 12312455"); + EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식", "토스뱅크", "12312455"); given(eventService.findEvent(eventId)).willReturn(eventDetailAppResponse); mockMvc.perform(get("/api/events/{eventId}", eventId)) @@ -73,7 +73,8 @@ void findEventTest() throws Exception { ), responseFields( fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름"), - fieldWithPath("account").type(JsonFieldType.STRING).description("행사 계좌") + fieldWithPath("bankName").type(JsonFieldType.STRING).description("토스뱅크"), + fieldWithPath("accountNumber").type(JsonFieldType.STRING).description("12312455") ) ) ); diff --git a/server/src/test/java/server/haengdong/domain/event/EventTest.java b/server/src/test/java/server/haengdong/domain/event/EventTest.java index 83cd700a0..67c5420b0 100644 --- a/server/src/test/java/server/haengdong/domain/event/EventTest.java +++ b/server/src/test/java/server/haengdong/domain/event/EventTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -81,7 +82,10 @@ void changeAccountTest() { event.changeAccount("토스뱅크", "12345678"); - assertThat(event.getAccount()).isEqualTo("토스뱅크 12345678"); + assertAll( + () -> assertThat(event.getBankName()).isEqualTo("토스뱅크"), + () -> assertThat(event.getAccountNumber()).isEqualTo("12345678") + ); } @DisplayName("계좌 정보에 은행 이름과 계좌 번호가 모두 포함되지 않으면 예외가 발생한다.") @@ -132,4 +136,30 @@ void changeAccountTest5(String accountNumber) { assertThatThrownBy(() -> event.changeAccount("토스뱅크", accountNumber)) .isInstanceOf(HaengdongException.class); } + + @DisplayName("계좌 정보를 조회한다.") + @Test + void getBankNameTest() { + Event event = new Event("이름", "1234", "TEST_TOKEN"); + + event.changeAccount("토스뱅크", "12345678"); + + assertAll( + () -> assertThat(event.getBankName()).isEqualTo("토스뱅크"), + () -> assertThat(event.getAccountNumber()).isEqualTo("12345678") + ); + } + + @DisplayName("계좌 번호에 공백이 있어도 계좌 정보를 정상적으로 조회한다.") + @Test + void getBankNameTest1() { + Event event = new Event("이름", "1234", "TEST_TOKEN"); + + event.changeAccount("토스뱅크", "1234 5678 9012"); + + assertAll( + () -> assertThat(event.getBankName()).isEqualTo("토스뱅크"), + () -> assertThat(event.getAccountNumber()).isEqualTo("1234 5678 9012") + ); + } } diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java index f1f11d4a6..5facbb740 100644 --- a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java @@ -29,7 +29,7 @@ class EventControllerTest extends ControllerTestSupport { @Test void findEventTest() throws Exception { String eventId = "망쵸토큰"; - EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식", "토스 1231245"); + EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식", "토스뱅크", "1231245"); given(eventService.findEvent(eventId)).willReturn(eventDetailAppResponse); mockMvc.perform(get("/api/events/{eventId}", eventId)) From f20eb8ebe02a523fa042a907090624c604e7b14e Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Wed, 25 Sep 2024 09:28:51 +0900 Subject: [PATCH 175/178] =?UTF-8?q?feat:=20=EC=BF=BC=EB=A6=AC=20=EC=B5=9C?= =?UTF-8?q?=EC=A0=81=ED=99=94=20(#598)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/haengdong/domain/bill/Bill.java | 1 - .../domain/bill/BillDetailRepository.java | 10 --- .../haengdong/domain/bill/BillRepository.java | 17 +++++ .../application/BillServiceTest.java | 71 +++++++++++++++---- 4 files changed, 75 insertions(+), 24 deletions(-) diff --git a/server/src/main/java/server/haengdong/domain/bill/Bill.java b/server/src/main/java/server/haengdong/domain/bill/Bill.java index 69be84523..6face8274 100644 --- a/server/src/main/java/server/haengdong/domain/bill/Bill.java +++ b/server/src/main/java/server/haengdong/domain/bill/Bill.java @@ -33,7 +33,6 @@ public class Bill { private static final int MAX_TITLE_LENGTH = 30; private static final long MIN_PRICE = 1L; private static final long MAX_PRICE = 10_000_000L; - private static final long DEFAULT_PRICE = 0L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/server/src/main/java/server/haengdong/domain/bill/BillDetailRepository.java b/server/src/main/java/server/haengdong/domain/bill/BillDetailRepository.java index d49c01ab2..7d656783b 100644 --- a/server/src/main/java/server/haengdong/domain/bill/BillDetailRepository.java +++ b/server/src/main/java/server/haengdong/domain/bill/BillDetailRepository.java @@ -1,6 +1,5 @@ package server.haengdong.domain.bill; -import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; @@ -11,15 +10,6 @@ @Repository public interface BillDetailRepository extends JpaRepository<BillDetail, Long> { - List<BillDetail> findAllByBill(Bill bill); - - @Query(""" - select bd from BillDetail bd - join fetch bd.member - where bd.bill.id = :billId - """) - List<BillDetail> findAllByBillId(Long billId); - @Modifying @Query("delete from BillDetail bd where bd.member = :member") void deleteAllByMember(@Param("member") Member member); diff --git a/server/src/main/java/server/haengdong/domain/bill/BillRepository.java b/server/src/main/java/server/haengdong/domain/bill/BillRepository.java index 2c0b16956..bbafbb4db 100644 --- a/server/src/main/java/server/haengdong/domain/bill/BillRepository.java +++ b/server/src/main/java/server/haengdong/domain/bill/BillRepository.java @@ -3,13 +3,30 @@ import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import server.haengdong.domain.event.Event; @Repository public interface BillRepository extends JpaRepository<Bill, Long> { + @Query(""" + select b + from Bill b + join fetch b.billDetails bd + join fetch bd.member + where b.event = :event + """) List<Bill> findAllByEvent(Event event); + @Query(""" + select b + from Bill b + join fetch b.billDetails bd + join fetch bd.member + where b.event = :event + order by b.id desc + limit 1 + """) Optional<Bill> findFirstByEventOrderByIdDesc(Event event); } diff --git a/server/src/test/java/server/haengdong/application/BillServiceTest.java b/server/src/test/java/server/haengdong/application/BillServiceTest.java index 72fd0192f..347e6712a 100644 --- a/server/src/test/java/server/haengdong/application/BillServiceTest.java +++ b/server/src/test/java/server/haengdong/application/BillServiceTest.java @@ -22,10 +22,10 @@ import server.haengdong.domain.bill.BillDetail; import server.haengdong.domain.bill.BillDetailRepository; import server.haengdong.domain.bill.BillRepository; -import server.haengdong.domain.member.Member; -import server.haengdong.domain.member.MemberRepository; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; +import server.haengdong.domain.member.Member; +import server.haengdong.domain.member.MemberRepository; import server.haengdong.exception.HaengdongException; import server.haengdong.support.fixture.Fixture; @@ -51,25 +51,67 @@ class BillServiceTest extends ServiceTestSupport { void findSteps() { Event event = Fixture.EVENT1; eventRepository.save(event); - Member member = new Member(event, "토다리"); - memberRepository.save(member); - Bill bill = Bill.create(event, "행동대장 회식", 100000L, List.of(member)); - billRepository.save(bill); + Member member1 = new Member(event, "토다리"); + Member member2 = new Member(event, "쿠키"); + Member member3 = new Member(event, "소하"); + Member member4 = new Member(event, "웨디"); + memberRepository.saveAll(List.of(member1, member2, member3, member4)); + Bill bill1 = Bill.create(event, "행동대장 회식1", 100000L, List.of(member1, member2, member3)); + Bill bill2 = Bill.create(event, "행동대장 회식2", 200000L, List.of(member1, member2, member3, member4)); + Bill bill3 = Bill.create(event, "행동대장 회식3", 300000L, List.of(member1, member2, member3, member4)); + Bill bill4 = Bill.create(event, "행동대장 회식4", 400000L, List.of(member2, member3, member4)); + billRepository.saveAll(List.of(bill1, bill2, bill3, bill4)); List<StepAppResponse> steps = billService.findSteps(event.getToken()); + assertThat(steps).hasSize(3); + assertThat(steps.get(0).bills()).hasSize(1) .extracting(BillAppResponse::id, BillAppResponse::title, BillAppResponse::price, BillAppResponse::isFixed) .containsExactlyInAnyOrder( - tuple(bill.getId(), bill.getTitle(), bill.getPrice(), bill.isFixed()) + tuple(bill1.getId(), bill1.getTitle(), bill1.getPrice(), bill1.isFixed()) + ); + + assertThat(steps.get(0).members()).hasSize(3) + .extracting(MemberAppResponse::id, MemberAppResponse::name) + .containsExactlyInAnyOrder( + tuple(member1.getId(), member1.getName()), + tuple(member2.getId(), member2.getName()), + tuple(member3.getId(), member3.getName()) + ); + + assertThat(steps.get(1).bills()).hasSize(2) + .extracting(BillAppResponse::id, BillAppResponse::title, BillAppResponse::price, + BillAppResponse::isFixed) + .containsExactlyInAnyOrder( + tuple(bill2.getId(), bill2.getTitle(), bill2.getPrice(), bill2.isFixed()), + tuple(bill3.getId(), bill3.getTitle(), bill3.getPrice(), bill3.isFixed()) ); - assertThat(steps.get(0).members()).hasSize(1) + assertThat(steps.get(1).members()).hasSize(4) .extracting(MemberAppResponse::id, MemberAppResponse::name) .containsExactlyInAnyOrder( - tuple(member.getId(), member.getName()) + tuple(member1.getId(), member1.getName()), + tuple(member2.getId(), member2.getName()), + tuple(member3.getId(), member3.getName()), + tuple(member4.getId(), member4.getName()) ); + + assertThat(steps.get(2).bills()).hasSize(1) + .extracting(BillAppResponse::id, BillAppResponse::title, BillAppResponse::price, + BillAppResponse::isFixed) + .containsExactlyInAnyOrder( + tuple(bill4.getId(), bill4.getTitle(), bill4.getPrice(), bill4.isFixed()) + ); + + assertThat(steps.get(2).members()).hasSize(3) + .extracting(MemberAppResponse::id, MemberAppResponse::name) + .containsExactlyInAnyOrder( + tuple(member2.getId(), member2.getName()), + tuple(member3.getId(), member3.getName()), + tuple(member4.getId(), member4.getName()) + ); } @DisplayName("지출 내역을 생성한다.") @@ -109,7 +151,9 @@ void saveBillTest1() { billService.saveBill(event.getToken(), request); - List<BillDetail> billDetails = billDetailRepository.findAllByBillId(1L); + List<Bill> bills = billRepository.findAllByEvent(event); + + List<BillDetail> billDetails = bills.get(0).getBillDetails(); assertThat(billDetails) .hasSize(2) @@ -195,8 +239,8 @@ void updateBill2() { billService.updateBill(event.getToken(), bill.getId(), request); - Bill updatedBill = billRepository.findById(bill.getId()).get(); - List<BillDetail> billDetails = billDetailRepository.findAllByBill(updatedBill); + Bill updatedBill = billRepository.findAllByEvent(event).get(0); + List<BillDetail> billDetails = updatedBill.getBillDetails(); assertThat(billDetails).hasSize(4) .extracting(BillDetail::getPrice) @@ -272,7 +316,8 @@ void updateBillDetailsTest2() { billService.updateBillDetails(event1.getToken(), bill.getId(), request); - List<BillDetail> foundBillDetails = billDetailRepository.findAllByBill(bill); + Bill foundBill = billRepository.findAllByEvent(event1).get(0); + List<BillDetail> foundBillDetails = foundBill.getBillDetails(); assertThat(foundBillDetails).hasSize(2) .extracting(BillDetail::getId, BillDetail::getPrice) From 6cc464a3ea57b5caeaf61222a575896c48d0c87a Mon Sep 17 00:00:00 2001 From: juha <84626225+khabh@users.noreply.github.com> Date: Wed, 25 Sep 2024 10:42:26 +0900 Subject: [PATCH 176/178] =?UTF-8?q?feat:=20=EB=A9=A4=EB=B2=84=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=88=98=EC=A0=95=20API=20=ED=98=B8=EC=B6=9C=20?= =?UTF-8?q?=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95=20(#610)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 멤버 정보 수정 기능 검증 로직 수정 * refactor: 예외 메시지 수정 * test: 예외 메시지에 맞게 테스트 수정 --- server/src/docs/asciidoc/member.adoc | 4 +- .../haengdong/application/MemberService.java | 24 +++++++++--- .../haengdong/domain/member/Member.java | 7 +++- .../exception/HaengdongErrorCode.java | 1 + .../application/MemberServiceTest.java | 37 +++++++++++++++---- 5 files changed, 57 insertions(+), 16 deletions(-) diff --git a/server/src/docs/asciidoc/member.adoc b/server/src/docs/asciidoc/member.adoc index 230db1906..e37a57d57 100644 --- a/server/src/docs/asciidoc/member.adoc +++ b/server/src/docs/asciidoc/member.adoc @@ -106,8 +106,8 @@ operation::updateMembers[snippets="path-parameters,http-request,request-body,req "message":"존재하지 않는 행사입니다." }, { - "code": "MEMBER_NOT_FOUND", - "message": "존재하지 않는 참여자입니다." + "code": "MEMBER_UPDATE_MISMATCH", + "message": "업데이트 요청된 참여자 정보와 기존 행사 참여자 정보가 일치하지 않습니다." }, { "code": "MEMBER_NAME_DUPLICATE", diff --git a/server/src/main/java/server/haengdong/application/MemberService.java b/server/src/main/java/server/haengdong/application/MemberService.java index 7b439ada0..9da74972a 100644 --- a/server/src/main/java/server/haengdong/application/MemberService.java +++ b/server/src/main/java/server/haengdong/application/MemberService.java @@ -1,9 +1,12 @@ package server.haengdong.application; + +import static java.util.stream.Collectors.toMap; + import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -129,27 +132,36 @@ private void validateMemberUnique(List<MemberUpdateAppRequest> members) { } private void validateUpdatedMembersExist(List<Member> eventMembers, List<Member> updatedMembers) { + if (updatedMembers.size() != eventMembers.size()) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_UPDATE_MISMATCH); + } Set<Member> members = new HashSet<>(eventMembers); if (!members.containsAll(updatedMembers)) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NOT_FOUND); + throw new HaengdongException(HaengdongErrorCode.MEMBER_UPDATE_MISMATCH); } } private void validateUpdatedNamesUnique(List<Member> eventMembers, List<Member> updatedMembers) { - Set<String> eventMemberNames = eventMembers.stream() - .map(Member::getName) - .collect(Collectors.toSet()); + Map<Long, String> eventMemberNames = eventMembers.stream() + .collect(toMap(Member::getId, Member::getName)); + Set<String> existNames = new HashSet<>(eventMemberNames.values()); boolean memberNameDuplicated = updatedMembers.stream() + .filter(updatedMember -> isMemberNameUpdated(eventMemberNames, updatedMember)) .map(Member::getName) - .anyMatch(eventMemberNames::contains); + .anyMatch(existNames::contains); if (memberNameDuplicated) { throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); } } + private boolean isMemberNameUpdated(Map<Long, String> eventMemberNames, Member updatedMember) { + String prevMemberName = eventMemberNames.get(updatedMember.getId()); + return !updatedMember.hasName(prevMemberName); + } + @Transactional public void deleteMember(String token, Long memberId) { memberRepository.findById(memberId) diff --git a/server/src/main/java/server/haengdong/domain/member/Member.java b/server/src/main/java/server/haengdong/domain/member/Member.java index 7180d57e4..25a19ccb0 100644 --- a/server/src/main/java/server/haengdong/domain/member/Member.java +++ b/server/src/main/java/server/haengdong/domain/member/Member.java @@ -56,10 +56,15 @@ public Member(Long id, Event event, String name, boolean isDeposited) { private void validateName(String name) { int nameLength = name.length(); if (nameLength < MIN_NAME_LENGTH || nameLength > MAX_NAME_LENGTH) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_LENGTH_INVALID, MIN_NAME_LENGTH, MAX_NAME_LENGTH); + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_LENGTH_INVALID, MIN_NAME_LENGTH, + MAX_NAME_LENGTH); } } + public boolean hasName(String name) { + return this.name.equals(name); + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java index 7030c4907..1fcebd225 100644 --- a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java +++ b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java @@ -19,6 +19,7 @@ public enum HaengdongErrorCode { MEMBER_NOT_FOUND("존재하지 않는 참여자입니다."), MEMBER_ALREADY_EXIST("현재 참여하고 있는 인원이 존재합니다."), MEMBER_NAME_CHANGE_DUPLICATE("중복된 참여 인원 이름 변경 요청이 존재합니다."), + MEMBER_UPDATE_MISMATCH("업데이트 요청된 참여자 ID 목록과 기존 행사 참여자 ID 목록이 일치하지 않습니다."), BILL_NOT_FOUND("존재하지 않는 지출입니다."), BILL_TITLE_INVALID("앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다."), diff --git a/server/src/test/java/server/haengdong/application/MemberServiceTest.java b/server/src/test/java/server/haengdong/application/MemberServiceTest.java index 62bb7a0b8..767dde440 100644 --- a/server/src/test/java/server/haengdong/application/MemberServiceTest.java +++ b/server/src/test/java/server/haengdong/application/MemberServiceTest.java @@ -4,6 +4,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.tuple; import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static server.haengdong.support.fixture.Fixture.BILL1; import static server.haengdong.support.fixture.Fixture.EVENT1; @@ -30,10 +31,10 @@ import server.haengdong.domain.bill.BillDetail; import server.haengdong.domain.bill.BillDetailRepository; import server.haengdong.domain.bill.BillRepository; -import server.haengdong.domain.member.Member; -import server.haengdong.domain.member.MemberRepository; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; +import server.haengdong.domain.member.Member; +import server.haengdong.domain.member.MemberRepository; import server.haengdong.exception.HaengdongException; class MemberServiceTest extends ServiceTestSupport { @@ -146,7 +147,7 @@ void deleteMemberTest1() { assertThatThrownBy(() -> memberService.deleteMember(event1.getToken(), member.getId())) .isInstanceOf(HaengdongException.class); - + assertThat(memberRepository.findById(member.getId())).isNotEmpty(); } @@ -190,9 +191,9 @@ private BillDetail getDetailByMember(Bill bill, Member member) { .orElseThrow(); } - @DisplayName("멤버 정보를 수정한다.") + @DisplayName("멤버 이름 정보를 수정한다.") @Test - void updateMembersTest() { + void updateMembersNameTest() { Event event = EVENT1; Member member = MEMBER1; eventRepository.save(event); @@ -212,6 +213,28 @@ void updateMembersTest() { ); } + @DisplayName("멤버 정보를 수정한다.") + @Test + void updateMembersIsDepositedTest() { + Event event = EVENT1; + Member member = MEMBER1; + eventRepository.save(event); + memberRepository.save(member); + MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( + List.of( + new MemberUpdateAppRequest(member.getId(), member.getName(), false) + ) + ); + + memberService.updateMembers(event.getToken(), membersUpdateAppRequest); + + Member updatedMember = memberRepository.findById(member.getId()).orElseThrow(); + assertAll( + () -> assertThat(updatedMember.getName()).isEqualTo(member.getName()), + () -> assertFalse(updatedMember.isDeposited()) + ); + } + @DisplayName("수정할 멤버 id가 중복된 경우 예외가 발생한다.") @Test void updateMembersTest2() { @@ -267,7 +290,7 @@ void updateMembersTest4() { assertThatThrownBy(() -> memberService.updateMembers(event1.getToken(), membersUpdateAppRequest)) .isInstanceOf(HaengdongException.class) - .hasMessage("존재하지 않는 참여자입니다."); + .hasMessage("업데이트 요청된 참여자 ID 목록과 기존 행사 참여자 ID 목록이 일치하지 않습니다."); } @DisplayName("수정하려는 행사 참여 인원 이름이 이미 존재하는 경우 예외가 발생한다.") @@ -286,7 +309,7 @@ void updateMembersTest5() { assertThatThrownBy(() -> memberService.updateMembers(event1.getToken(), membersUpdateAppRequest)) .isInstanceOf(HaengdongException.class) - .hasMessage("중복된 행사 참여 인원 이름이 존재합니다."); + .hasMessage("업데이트 요청된 참여자 ID 목록과 기존 행사 참여자 ID 목록이 일치하지 않습니다."); } @DisplayName("참여자 간 서로의 이름으로 수정하려는 경우 예외가 발생한다.") From 8605c78fa8beb32ad290f6814b741c9c46048232 Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Thu, 26 Sep 2024 14:50:36 +0900 Subject: [PATCH 177/178] =?UTF-8?q?refactor:=20API=20=EB=AA=85=EC=84=B8?= =?UTF-8?q?=EC=84=9C=EC=97=90=20=EC=9E=91=EC=84=B1=EB=90=9C=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EC=B5=9C=EC=8B=A0=ED=99=94=20=EB=B0=8F=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=88=98=EC=A0=95=20(#645)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/haengdong/exception/HaengdongErrorCode.java | 7 +++---- .../presentation/request/BillDetailUpdateRequest.java | 1 - .../haengdong/presentation/request/MemberSaveRequest.java | 8 +++++++- .../server/haengdong/application/MemberServiceTest.java | 4 ++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java index 1fcebd225..a59288f4b 100644 --- a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java +++ b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java @@ -14,8 +14,8 @@ public enum HaengdongErrorCode { BANK_NAME_INVALID("지원하지 않는 은행입니다. 지원하는 은행 목록: %s"), ACCOUNT_LENGTH_INVALID("계좌번호는 %d자 이상 %d자 이하만 입력 가능합니다."), - MEMBER_NAME_LENGTH_INVALID("멤버 이름은 %d자 이상 %d자 이하만 입력 가능합니다."), - MEMBER_NAME_DUPLICATE("중복된 행사 참여 인원 이름이 존재합니다."), + MEMBER_NAME_LENGTH_INVALID("참여자 이름은 %d자 이상 %d자 이하만 입력 가능합니다."), + MEMBER_NAME_DUPLICATE("행사에 중복된 참여자 이름이 존재합니다."), MEMBER_NOT_FOUND("존재하지 않는 참여자입니다."), MEMBER_ALREADY_EXIST("현재 참여하고 있는 인원이 존재합니다."), MEMBER_NAME_CHANGE_DUPLICATE("중복된 참여 인원 이름 변경 요청이 존재합니다."), @@ -27,14 +27,13 @@ public enum HaengdongErrorCode { BILL_DETAIL_NOT_FOUND("존재하지 않는 참여자 지출입니다."), BILL_PRICE_NOT_MATCHED("지출 총액이 일치하지 않습니다."), - DIFFERENT_STEP_MEMBERS("회원 목록이 일치하지 않습니다."), + DIFFERENT_STEP_MEMBERS("참여자 목록이 일치하지 않습니다."), /* Authentication */ PASSWORD_INVALID("비밀번호가 일치하지 않습니다."), TOKEN_NOT_FOUND("토큰이 존재하지 않습니다."), - TOKEN_EXPIRED("만료된 토큰입니다."), TOKEN_INVALID("유효하지 않은 토큰입니다."), FORBIDDEN("접근할 수 없는 행사입니다."), diff --git a/server/src/main/java/server/haengdong/presentation/request/BillDetailUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillDetailUpdateRequest.java index accaf8e00..de670f28f 100644 --- a/server/src/main/java/server/haengdong/presentation/request/BillDetailUpdateRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/BillDetailUpdateRequest.java @@ -11,7 +11,6 @@ public record BillDetailUpdateRequest( @NotNull(message = "지출 금액은 공백일 수 없습니다.") Long price, - @NotNull(message = "지출 금액은 공백일 수 없습니다.") boolean isFixed ) { public BillDetailUpdateAppRequest toAppRequest() { diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberSaveRequest.java index f1d75e1b1..8b763be09 100644 --- a/server/src/main/java/server/haengdong/presentation/request/MemberSaveRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/MemberSaveRequest.java @@ -1,4 +1,10 @@ package server.haengdong.presentation.request; -public record MemberSaveRequest(String name) { +import jakarta.validation.constraints.NotBlank; + +public record MemberSaveRequest( + + @NotBlank(message = "참여자 이름은 공백일 수 없습니다.") + String name +) { } diff --git a/server/src/test/java/server/haengdong/application/MemberServiceTest.java b/server/src/test/java/server/haengdong/application/MemberServiceTest.java index 767dde440..099326317 100644 --- a/server/src/test/java/server/haengdong/application/MemberServiceTest.java +++ b/server/src/test/java/server/haengdong/application/MemberServiceTest.java @@ -120,7 +120,7 @@ void saveMembersTest2() { assertThatThrownBy(() -> memberService.saveMembers(event.getToken(), request)) .isInstanceOf(HaengdongException.class) - .hasMessageContaining("중복된 행사 참여 인원 이름이 존재합니다."); + .hasMessageContaining("행사에 중복된 참여자 이름이 존재합니다."); } @DisplayName("행사 참여 인원을 삭제한다.") @@ -329,7 +329,7 @@ void updateMembersTest6() { assertThatThrownBy(() -> memberService.updateMembers(event.getToken(), membersUpdateAppRequest)) .isInstanceOf(HaengdongException.class) - .hasMessage("중복된 행사 참여 인원 이름이 존재합니다."); + .hasMessage("행사에 중복된 참여자 이름이 존재합니다."); } @DisplayName("행사에 참여한 전체 인원을 조회한다.") From 89ed4257776c5fb6252b4a2d5231859a009b456c Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Thu, 26 Sep 2024 17:15:12 +0900 Subject: [PATCH 178/178] =?UTF-8?q?refactor:=20=ED=96=89=EC=82=AC=20?= =?UTF-8?q?=EC=B0=B8=EC=97=AC=EC=9E=90=20=EC=A0=84=EC=B2=B4=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EB=A1=9C=EC=A7=81=20=EB=A6=AC=ED=8E=99=ED=86=A0?= =?UTF-8?q?=EB=A7=81=20(#644)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 행사 참여자 전체 수정 로직 리펙토링 * refactor: 메소드 분리 * refactor: UpdatedMembers 로 변경 * refactor: CurrentMember 쿼리 변경 * refactor: 변수명 변경 * test: 예외 메시지 변경 * style: 메소드 명 변경 * refactor: 배치 사이즈 조절 * refactor: Set 으로 변경 * refactor: 메소드 순서 변경 * refactor: 필요없는 객체 제거 * docs: 운영 배포 워크플로 수정 * docs: 도커 이미지 이름 변경 --- .github/workflows/backend-prod.yml | 25 +++- .../haengdong/application/MemberService.java | 117 ++++------------- .../request/MembersUpdateAppRequest.java | 8 ++ .../domain/bill/BillDetailRepository.java | 16 --- .../haengdong/domain/bill/BillRepository.java | 9 -- .../domain/member/UpdatedMembers.java | 67 ++++++++++ server/src/main/resources/application.yml | 1 + .../application/BillServiceTest.java | 4 - .../application/MemberServiceTest.java | 17 +-- .../domain/member/UpdatedMembersTest.java | 118 ++++++++++++++++++ 10 files changed, 251 insertions(+), 131 deletions(-) delete mode 100644 server/src/main/java/server/haengdong/domain/bill/BillDetailRepository.java create mode 100644 server/src/main/java/server/haengdong/domain/member/UpdatedMembers.java create mode 100644 server/src/test/java/server/haengdong/domain/member/UpdatedMembersTest.java diff --git a/.github/workflows/backend-prod.yml b/.github/workflows/backend-prod.yml index f7daacd33..4134bde1e 100644 --- a/.github/workflows/backend-prod.yml +++ b/.github/workflows/backend-prod.yml @@ -54,9 +54,9 @@ jobs: docker buildx build --platform linux/arm64 -t \ ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }} --push . - deploy: + deploy-prod-1: needs: build - runs-on: [ self-hosted, backend-prod ] + runs-on: [ self-hosted, backend-prod-1 ] steps: - name: Docker remove run: | @@ -71,4 +71,23 @@ jobs: run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }} - name: Docker run - run: sudo docker run -d -p 8080:8080 -e SPRING_PROFILES_ACTIVE=prod -v log-volume:/app/logs --name haengdong-backend ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }} + run: sudo docker run -d -p 80:8080 -e SPRING_PROFILES_ACTIVE=prod -v log-volume:/app/logs --name haengdong-backend ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }} + + deploy-prod-2: + needs: build + runs-on: [ self-hosted, backend-prod-2 ] + steps: + - name: Docker remove + run: | + CONTAINER_IDS=$(sudo docker ps -qa) + if [ -n "$CONTAINER_IDS" ]; then + sudo docker rm -f $CONTAINER_IDS + else + echo "No running containers found." + fi + + - name: Docker Image pull + run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }} + + - name: Docker run + run: sudo docker run -d -p 80:8080 -e SPRING_PROFILES_ACTIVE=prod -v log-volume:/app/logs --name haengdong-backend ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }} diff --git a/server/src/main/java/server/haengdong/application/MemberService.java b/server/src/main/java/server/haengdong/application/MemberService.java index 9da74972a..840c4f769 100644 --- a/server/src/main/java/server/haengdong/application/MemberService.java +++ b/server/src/main/java/server/haengdong/application/MemberService.java @@ -1,29 +1,24 @@ package server.haengdong.application; -import static java.util.stream.Collectors.toMap; - -import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import server.haengdong.application.request.MemberSaveAppRequest; -import server.haengdong.application.request.MemberUpdateAppRequest; import server.haengdong.application.request.MembersSaveAppRequest; import server.haengdong.application.request.MembersUpdateAppRequest; import server.haengdong.application.response.MemberAppResponse; import server.haengdong.application.response.MembersDepositAppResponse; import server.haengdong.application.response.MembersSaveAppResponse; import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.bill.BillDetailRepository; import server.haengdong.domain.bill.BillRepository; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.domain.member.Member; import server.haengdong.domain.member.MemberRepository; +import server.haengdong.domain.member.UpdatedMembers; import server.haengdong.exception.HaengdongErrorCode; import server.haengdong.exception.HaengdongException; @@ -35,7 +30,6 @@ public class MemberService { private final MemberRepository memberRepository; private final EventRepository eventRepository; private final BillRepository billRepository; - private final BillDetailRepository billDetailRepository; @Transactional public MembersSaveAppResponse saveMembers(String token, MembersSaveAppRequest request) { @@ -54,6 +48,21 @@ public MembersSaveAppResponse saveMembers(String token, MembersSaveAppRequest re return MembersSaveAppResponse.of(savedMembers); } + private void validateMemberSave(List<String> memberNames, Event event) { + Set<String> uniqueMemberNames = Set.copyOf(memberNames); + if (memberNames.size() != uniqueMemberNames.size()) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE, memberNames); + } + if (isDuplicatedMemberNames(uniqueMemberNames, event)) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_ALREADY_EXIST); + } + } + + private boolean isDuplicatedMemberNames(Set<String> uniqueMemberNames, Event event) { + return memberRepository.findAllByEvent(event).stream() + .anyMatch(member -> uniqueMemberNames.contains(member.getName())); + } + public List<MemberAppResponse> getCurrentMembers(String token) { Event event = getEvent(token); @@ -65,16 +74,6 @@ public List<MemberAppResponse> getCurrentMembers(String token) { .toList(); } - private void validateMemberSave(List<String> memberNames, Event event) { - if (memberNamesDuplicated(memberNames)) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE, memberNames); - } - if (memberRepository.findAllByEvent(event).stream() - .anyMatch(member -> memberNames.contains(member.getName()))) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_ALREADY_EXIST); - } - } - public MembersDepositAppResponse findAllMembers(String token) { Event event = getEvent(token); @@ -86,80 +85,11 @@ public MembersDepositAppResponse findAllMembers(String token) { @Transactional public void updateMembers(String token, MembersUpdateAppRequest request) { Event event = getEvent(token); - validateMemberUpdate(request); + UpdatedMembers updatedMembers = new UpdatedMembers(request.toMembers(event)); + List<Member> originMembers = memberRepository.findAllByEvent(event); - List<Member> updatedMembers = request.members().stream() - .map(memberRequest -> memberRequest.toMember(event)) - .toList(); - List<Member> eventMembers = memberRepository.findAllByEvent(event); - - validateUpdatedMembersExist(eventMembers, updatedMembers); - validateUpdatedNamesUnique(eventMembers, updatedMembers); - memberRepository.saveAll(updatedMembers); - } - - private Event getEvent(String token) { - return eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); - } - - private void validateMemberUpdate(MembersUpdateAppRequest request) { - validateChangedNameUnique(request.members()); - validateMemberUnique(request.members()); - } - - private void validateChangedNameUnique(List<MemberUpdateAppRequest> members) { - List<String> memberNames = members.stream() - .map(MemberUpdateAppRequest::name) - .toList(); - if (memberNamesDuplicated(memberNames)) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); - } - } - - private boolean memberNamesDuplicated(List<String> memberNames) { - return memberNames.size() != Set.copyOf(memberNames).size(); - } - - private void validateMemberUnique(List<MemberUpdateAppRequest> members) { - List<Long> memberIds = members.stream() - .map(MemberUpdateAppRequest::id) - .distinct() - .toList(); - if (members.size() != memberIds.size()) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); - } - } - - private void validateUpdatedMembersExist(List<Member> eventMembers, List<Member> updatedMembers) { - if (updatedMembers.size() != eventMembers.size()) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_UPDATE_MISMATCH); - } - Set<Member> members = new HashSet<>(eventMembers); - - if (!members.containsAll(updatedMembers)) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_UPDATE_MISMATCH); - } - } - - private void validateUpdatedNamesUnique(List<Member> eventMembers, List<Member> updatedMembers) { - Map<Long, String> eventMemberNames = eventMembers.stream() - .collect(toMap(Member::getId, Member::getName)); - Set<String> existNames = new HashSet<>(eventMemberNames.values()); - - boolean memberNameDuplicated = updatedMembers.stream() - .filter(updatedMember -> isMemberNameUpdated(eventMemberNames, updatedMember)) - .map(Member::getName) - .anyMatch(existNames::contains); - - if (memberNameDuplicated) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); - } - } - - private boolean isMemberNameUpdated(Map<Long, String> eventMemberNames, Member updatedMember) { - String prevMemberName = eventMemberNames.get(updatedMember.getId()); - return !updatedMember.hasName(prevMemberName); + updatedMembers.validateUpdatable(originMembers); + memberRepository.saveAll(updatedMembers.getMembers()); } @Transactional @@ -177,7 +107,12 @@ private void deleteMember(String token, Member member) { billRepository.findAllByEvent(event).stream() .filter(bill -> bill.containMember(member)) .forEach(bill -> bill.removeMemberBillDetail(member)); - billDetailRepository.deleteAllByMember(member); + billRepository.flush(); memberRepository.delete(member); } + + private Event getEvent(String token) { + return eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + } } diff --git a/server/src/main/java/server/haengdong/application/request/MembersUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/MembersUpdateAppRequest.java index a8ce8b893..aa3253504 100644 --- a/server/src/main/java/server/haengdong/application/request/MembersUpdateAppRequest.java +++ b/server/src/main/java/server/haengdong/application/request/MembersUpdateAppRequest.java @@ -1,6 +1,14 @@ package server.haengdong.application.request; import java.util.List; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.member.Member; public record MembersUpdateAppRequest(List<MemberUpdateAppRequest> members) { + + public List<Member> toMembers(Event event) { + return members.stream() + .map(memberRequest -> memberRequest.toMember(event)) + .toList(); + } } diff --git a/server/src/main/java/server/haengdong/domain/bill/BillDetailRepository.java b/server/src/main/java/server/haengdong/domain/bill/BillDetailRepository.java deleted file mode 100644 index 7d656783b..000000000 --- a/server/src/main/java/server/haengdong/domain/bill/BillDetailRepository.java +++ /dev/null @@ -1,16 +0,0 @@ -package server.haengdong.domain.bill; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Modifying; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; -import server.haengdong.domain.member.Member; - -@Repository -public interface BillDetailRepository extends JpaRepository<BillDetail, Long> { - - @Modifying - @Query("delete from BillDetail bd where bd.member = :member") - void deleteAllByMember(@Param("member") Member member); -} diff --git a/server/src/main/java/server/haengdong/domain/bill/BillRepository.java b/server/src/main/java/server/haengdong/domain/bill/BillRepository.java index bbafbb4db..23efe487c 100644 --- a/server/src/main/java/server/haengdong/domain/bill/BillRepository.java +++ b/server/src/main/java/server/haengdong/domain/bill/BillRepository.java @@ -19,14 +19,5 @@ public interface BillRepository extends JpaRepository<Bill, Long> { """) List<Bill> findAllByEvent(Event event); - @Query(""" - select b - from Bill b - join fetch b.billDetails bd - join fetch bd.member - where b.event = :event - order by b.id desc - limit 1 - """) Optional<Bill> findFirstByEventOrderByIdDesc(Event event); } diff --git a/server/src/main/java/server/haengdong/domain/member/UpdatedMembers.java b/server/src/main/java/server/haengdong/domain/member/UpdatedMembers.java new file mode 100644 index 000000000..3a588c077 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/member/UpdatedMembers.java @@ -0,0 +1,67 @@ +package server.haengdong.domain.member; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +public class UpdatedMembers { + + private final Set<Member> members; + + public UpdatedMembers(List<Member> members) { + validateMemberUnique(members); + validateNameUnique(members); + this.members = new HashSet<>(members); + } + + private void validateMemberUnique(List<Member> members) { + if (members.size() != Set.copyOf(members).size()) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); + } + } + + private void validateNameUnique(List<Member> members) { + Set<String> uniqueNames = members.stream() + .map(Member::getName) + .collect(Collectors.toSet()); + if (members.size() != uniqueNames.size()) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); + } + } + + public void validateUpdatable(List<Member> originMembers) { + Set<Member> uniqueMembers = Set.copyOf(originMembers); + validateUpdatedMembersExist(uniqueMembers); + validateUpdatedNamesUnique(uniqueMembers); + } + + private void validateUpdatedMembersExist(Set<Member> originMembers) { + if (!this.members.equals(originMembers)) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_UPDATE_MISMATCH); + } + } + + private void validateUpdatedNamesUnique(Set<Member> originMembers) { + boolean duplicated = originMembers.stream() + .anyMatch(this::isMemberNameUpdated); + + if (duplicated) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); + } + } + + private boolean isMemberNameUpdated(Member originMembers) { + return this.members.stream() + .filter(member -> !member.getId().equals(originMembers.getId())) + .anyMatch(member -> member.hasName(originMembers.getName())); + } + + public List<Member> getMembers() { + return members.stream().toList(); + } +} + + diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index 2ae503547..22c337545 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -15,6 +15,7 @@ spring: ddl-auto: create properties: hibernate: + default_batch_fetch_size: 30 format_sql: true jdbc.time_zone: Asia/Seoul show-sql: true diff --git a/server/src/test/java/server/haengdong/application/BillServiceTest.java b/server/src/test/java/server/haengdong/application/BillServiceTest.java index 347e6712a..6d2b7aa8d 100644 --- a/server/src/test/java/server/haengdong/application/BillServiceTest.java +++ b/server/src/test/java/server/haengdong/application/BillServiceTest.java @@ -20,7 +20,6 @@ import server.haengdong.application.response.StepAppResponse; import server.haengdong.domain.bill.Bill; import server.haengdong.domain.bill.BillDetail; -import server.haengdong.domain.bill.BillDetailRepository; import server.haengdong.domain.bill.BillRepository; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; @@ -40,9 +39,6 @@ class BillServiceTest extends ServiceTestSupport { @Autowired private BillRepository billRepository; - @Autowired - private BillDetailRepository billDetailRepository; - @Autowired private MemberRepository memberRepository; diff --git a/server/src/test/java/server/haengdong/application/MemberServiceTest.java b/server/src/test/java/server/haengdong/application/MemberServiceTest.java index 099326317..662156a33 100644 --- a/server/src/test/java/server/haengdong/application/MemberServiceTest.java +++ b/server/src/test/java/server/haengdong/application/MemberServiceTest.java @@ -29,7 +29,6 @@ import server.haengdong.application.response.MembersSaveAppResponse; import server.haengdong.domain.bill.Bill; import server.haengdong.domain.bill.BillDetail; -import server.haengdong.domain.bill.BillDetailRepository; import server.haengdong.domain.bill.BillRepository; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; @@ -51,9 +50,6 @@ class MemberServiceTest extends ServiceTestSupport { @Autowired private BillRepository billRepository; - @Autowired - private BillDetailRepository billDetailRepository; - @DisplayName("행사에 참여자를 추가한다.") @Test void saveMembersTest() { @@ -171,12 +167,15 @@ void deleteMemberTest2() { billRepository.save(bill); memberService.deleteMember(event1.getToken(), member1.getId()); + Bill bill1 = billRepository.findAllByEvent(event1).get(0); + List<BillDetail> bill1Details = bill1.getBillDetails(); assertAll( () -> assertThat(memberRepository.findById(member1.getId())).isEmpty(), - () -> assertThat(billDetailRepository.findById(billDetail1.getId())).isEmpty(), + () -> assertThat(bill1Details).doesNotContain(billDetail1), () -> { - BillDetail foundDetail = billDetailRepository.findById(billDetail2.getId()).orElseThrow(); + BillDetail foundDetail = bill1Details.stream() + .filter(billDetail -> billDetail.isSameId(billDetail2.getId())).findFirst().get(); assertThat(foundDetail.getPrice()).isEqualTo(10000L); assertThat(foundDetail.isFixed()).isEqualTo(false); } @@ -362,10 +361,12 @@ void getCurrentMembersTest() { Member member1 = MEMBER1; Member member2 = MEMBER2; Member member3 = MEMBER3; - Bill bill = Bill.create(event, "title", 100000L, List.of(member1, member2, member3)); + Bill bill1 = Bill.create(event, "title1", 100000L, List.of(member1)); + Bill bill2 = Bill.create(event, "title2", 200000L, List.of(member1, member2, member3)); + Bill bill3 = Bill.create(event, "title2", 200000L, List.of(member1, member2, member3)); eventRepository.save(event); memberRepository.saveAll(List.of(member1, member2, member3)); - billRepository.save(bill); + billRepository.saveAll(List.of(bill1, bill2, bill3)); List<MemberAppResponse> currentMembers = memberService.getCurrentMembers(event.getToken()); diff --git a/server/src/test/java/server/haengdong/domain/member/UpdatedMembersTest.java b/server/src/test/java/server/haengdong/domain/member/UpdatedMembersTest.java new file mode 100644 index 000000000..9f0338ffb --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/member/UpdatedMembersTest.java @@ -0,0 +1,118 @@ +package server.haengdong.domain.member; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.domain.event.Event; +import server.haengdong.exception.HaengdongException; + +class UpdatedMembersTest { + + @DisplayName("이벤트 이름들은 중복될 수 없다.") + @Test + void validateNameUnique() { + Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); + List<Member> members = List.of( + new Member(1L, event, "고구마", false), + new Member(2L, event, "감자", false), + new Member(3L, event, "감자", false) + ); + + assertThatThrownBy(() -> new UpdatedMembers(members)) + .isInstanceOf(HaengdongException.class) + .hasMessage("중복된 참여 인원 이름 변경 요청이 존재합니다."); + } + + @DisplayName("이벤트 회원들은 중복될 수 없다.") + @Test + void validateMemberUnique() { + Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); + Member member1 = new Member(1L, event, "고구마", false); + Member member2 = new Member(2L, event, "감자", false); + List<Member> members = List.of(member1, member2, member2); + + + assertThatThrownBy(() -> new UpdatedMembers(members)) + .isInstanceOf(HaengdongException.class) + .hasMessage("중복된 참여 인원 이름 변경 요청이 존재합니다."); + } + + @DisplayName("이벤트 이름들로 이벤트 참여자들을 생성한다.") + @Test + void create() { + Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); + Member member1 = new Member(1L, event, "고구마", false); + Member member2 = new Member(2L, event, "감자", false); + Member member3 = new Member(3L, event, "당근", false); + List<Member> members = List.of(member1, member2, member3); + + UpdatedMembers eventUpdatedMembers = new UpdatedMembers(members); + assertThat(eventUpdatedMembers.getMembers()).hasSize(3) + .containsExactlyInAnyOrder(member1, member2, member3); + } + + @DisplayName("이벤트의 참여자들 전체가 존재하지 않으면 업데이트할 수 없다.") + @Test + void validateUpdatedMembersExist() { + Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); + Member member1 = new Member(1L, event, "고구마", false); + Member member2 = new Member(2L, event, "감자", false); + Member member3 = new Member(3L, event, "당근", false); + Member member4 = new Member(4L, event, "양파", false); + List<Member> members = List.of(member1, member2, member3, member4); + + Member updateMember1 = new Member(1L, event, "토다리", false); + Member updateMember2 = new Member(2L, event, "쿠키", false); + Member updateMember3 = new Member(3L, event, "백호", false); + UpdatedMembers updatedMembers = new UpdatedMembers(List.of(updateMember1, updateMember2, updateMember3)); + + assertThatThrownBy(() -> updatedMembers.validateUpdatable(members)) + .isInstanceOf(HaengdongException.class) + .hasMessage("업데이트 요청된 참여자 ID 목록과 기존 행사 참여자 ID 목록이 일치하지 않습니다."); + } + + @DisplayName("업데이트할 이름 중에 기존 이벤트의 참여자들의 이름과 중복되면 업데이트할 수 없다.") + @Test + void validateUpdatedNamesUnique() { + Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); + Member member1 = new Member(1L, event, "고구마", false); + Member member2 = new Member(2L, event, "감자", false); + Member member3 = new Member(3L, event, "당근", false); + Member member4 = new Member(4L, event, "양파", false); + List<Member> members = List.of(member1, member2, member3, member4); + + Member updateMember1 = new Member(1L, event, "토다리", false); + Member updateMember2 = new Member(2L, event, "쿠키", false); + Member updateMember3 = new Member(3L, event, "백호", false); + Member updateMember4 = new Member(4L, event, "감자", false); + UpdatedMembers updatedMembers = new UpdatedMembers(List.of(updateMember1, updateMember2, updateMember3, updateMember4)); + + assertThatThrownBy(() -> updatedMembers.validateUpdatable(members)) + .isInstanceOf(HaengdongException.class) + .hasMessage("행사에 중복된 참여자 이름이 존재합니다."); + } + + @DisplayName("이벤트의 참여자들 전체를 업데이트 검증한다.") + @Test + void validateUpdatable() { + Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); + Member member1 = new Member(1L, event, "고구마", false); + Member member2 = new Member(2L, event, "감자", false); + Member member3 = new Member(3L, event, "당근", false); + Member member4 = new Member(4L, event, "양파", false); + List<Member> members = List.of(member1, member2, member3, member4); + + Member updateMember1 = new Member(1L, event, "토다리", false); + Member updateMember2 = new Member(2L, event, "쿠키", false); + Member updateMember3 = new Member(3L, event, "백호", false); + Member updateMember4 = new Member(4L, event, "망쵸", false); + UpdatedMembers updatedMembers = new UpdatedMembers(List.of(updateMember1, updateMember2, updateMember3, updateMember4)); + + assertThatCode(() -> updatedMembers.validateUpdatable(members)) + .doesNotThrowAnyException(); + } +}