From 2937e29f908b9298fee694378db8288620a416f8 Mon Sep 17 00:00:00 2001 From: Grigoriy Gavrilov Date: Sun, 21 Sep 2025 11:20:27 +0300 Subject: [PATCH 001/109] =?UTF-8?q?=D0=92=D0=BE=D1=81=D1=81=D1=82=D0=B0?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D0=B8=D0=BB=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA?= =?UTF-8?q?=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env-dev | 6 ++++-- .../chatgpt/services/ConversationsService.java | 10 +++++----- .../java/com/chatgpt/services/DeepService.java | 16 ++++++++-------- .../src/main/resources/application.properties | 2 -- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.env-dev b/.env-dev index 0dbfc46e..f1d071a8 100644 --- a/.env-dev +++ b/.env-dev @@ -1,11 +1,13 @@ APP_SECRET_51802906=eNmBDWFYOm1Hl2aMIcbp APP_AUTH_KEY_51802906=b1aedf7ab1aedf7ab1aedf7a8fb2b8ac60bb1aeb1aedf7ad4ca7b89c13117db438121e0 CORS_ORIGIN=https://localhost:10888 -SKIP_AUTH=false +SKIP_AUTH=true POSTGRES_HOST=postgresql-dev -MODELS_URL=http://host.docker.internal:5000 +MODELS_URL=http://models-dev:5000 RAG_URL=http://host.docker.internal:5000 POSTGRES_USER=user POSTGRES_PASSWORD=user API_KEYS_5= +API_KEYS_120= +TG_TOKEN= IMAGES_API_KEY=* diff --git a/GPTutor-Backend/src/main/java/com/chatgpt/services/ConversationsService.java b/GPTutor-Backend/src/main/java/com/chatgpt/services/ConversationsService.java index d4653032..745a18e5 100644 --- a/GPTutor-Backend/src/main/java/com/chatgpt/services/ConversationsService.java +++ b/GPTutor-Backend/src/main/java/com/chatgpt/services/ConversationsService.java @@ -31,11 +31,11 @@ public class ConversationsService { @Value("${rag.url}") String ragUrl; - @Value("${master-token}") - String masterToken; +// @Value("${master-token}") +// String masterToken; - @Value("${deep-url}") - String deepUrl; +// @Value("${deep-url}") +// String deepUrl; @Autowired ApiRequestsService apiRequestsService; @@ -70,7 +70,7 @@ public void fetchCompletion(Utf8SseEmitter emitter, ConversationRequest conversa String input = mapper.writeValueAsString(chatGptRequest); HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(deepUrl + "/v1/chat/completions")) + .uri(URI.create("/v1/chat/completions")) .header("Content-Type", "application/json") .header("Authorization", "Bearer " + apiKey) .POST(HttpRequest.BodyPublishers.ofString(input)) diff --git a/GPTutor-Backend/src/main/java/com/chatgpt/services/DeepService.java b/GPTutor-Backend/src/main/java/com/chatgpt/services/DeepService.java index 7a019314..9f631772 100644 --- a/GPTutor-Backend/src/main/java/com/chatgpt/services/DeepService.java +++ b/GPTutor-Backend/src/main/java/com/chatgpt/services/DeepService.java @@ -12,12 +12,12 @@ @Service public class DeepService { - @Value("${master-token}") - String masterToken; +// @Value("${master-token}") +// String masterToken; - @Value("${deep-url}") - String deepUrl; +// @Value("${deep-url}") +// String deepUrl; public String getUserId() { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); @@ -33,7 +33,7 @@ public String getUserId() { public void updateUserToken(String operation, int amount) { String userId = this.getUserId(); - String url = String.format(deepUrl + "/token?userId=%s&masterToken=%s", userId, this.masterToken); + String url = String.format( "/token?userId=%s&masterToken=%s", userId, ""); System.out.println(url); RestTemplate restTemplate = new RestTemplate(); @@ -52,7 +52,7 @@ public String getUserToken() { String userId = this.getUserId(); System.out.println(userId); - String url = String.format(deepUrl + "/token?userId=%s&masterToken=%s", userId, this.masterToken); + String url = String.format("/token?userId=%s&masterToken=%s", userId, ""); System.out.println(url); RestTemplate restTemplate = new RestTemplate(); @@ -64,7 +64,7 @@ public String getUserToken() { public boolean hasUser() { String userId = this.getUserId(); - String url = String.format(deepUrl + "/token/has?userId=%s&masterToken=%s", userId, this.masterToken); + String url = String.format("/token/has?userId=%s&masterToken=%s", userId, ""); RestTemplate restTemplate = new RestTemplate(); @@ -85,7 +85,7 @@ public boolean hasUser() { String getAdminToken() { String userId = this.getUserId(); - String url = String.format(deepUrl + "/token?userId=%s&masterToken=%s", userId, this.masterToken); + String url = String.format("/token?userId=%s&masterToken=%s", userId, ""); RestTemplate restTemplate = new RestTemplate(); diff --git a/GPTutor-Backend/src/main/resources/application.properties b/GPTutor-Backend/src/main/resources/application.properties index 8d8f58b9..543fc8e9 100644 --- a/GPTutor-Backend/src/main/resources/application.properties +++ b/GPTutor-Backend/src/main/resources/application.properties @@ -1,8 +1,6 @@ spring.datasource.url=jdbc:postgresql://${POSTGRES_HOST}:5432/postgres models.url=${MODELS_URL} rag.url=${RAG_URL} -master-token=${MASTER_TOKEN} -deep-url=${DEEP_URL} tg-token=${TG_TOKEN} spring.datasource.username=${POSTGRES_USER} spring.datasource.password=${POSTGRES_PASSWORD} From 888681925ddb4b1d686e0c19bb6d81f656489104 Mon Sep 17 00:00:00 2001 From: Grigoriy Gavrilov Date: Sun, 21 Sep 2025 11:25:24 +0300 Subject: [PATCH 002/109] =?UTF-8?q?=D0=BF=D0=BE=D0=B4=D0=BD=D0=B8=D0=BC?= =?UTF-8?q?=D0=B5=D1=82=20=D0=B2=D0=B5=D1=80=D1=81=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- GPTutor-Frontend/package-lock.json | 259 ++++++++++++++++++----------- GPTutor-Frontend/package.json | 2 +- 2 files changed, 163 insertions(+), 98 deletions(-) diff --git a/GPTutor-Frontend/package-lock.json b/GPTutor-Frontend/package-lock.json index 62d85738..7698fa9c 100644 --- a/GPTutor-Frontend/package-lock.json +++ b/GPTutor-Frontend/package-lock.json @@ -24,7 +24,7 @@ "@vkontakte/vk-bridge": "^2.14.1", "@vkontakte/vk-bridge-react": "^1.0.1", "@vkontakte/vk-miniapps-deploy": "0.0.25", - "@vkontakte/vkui": "6.0.2", + "@vkontakte/vkui": "6.7.4", "babel-eslint": "^10.1.0", "cross-env": "7.0.3", "dignals": "0.1.0", @@ -2525,28 +2525,31 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz", - "integrity": "sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.1" + "@floating-ui/utils": "^0.2.10" } }, "node_modules/@floating-ui/dom": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.3.tgz", - "integrity": "sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", + "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.0.0", - "@floating-ui/utils": "^0.2.0" + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" } }, "node_modules/@floating-ui/react-dom": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.8.tgz", - "integrity": "sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", + "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", + "license": "MIT", "dependencies": { - "@floating-ui/dom": "^1.6.1" + "@floating-ui/dom": "^1.7.4" }, "peerDependencies": { "react": ">=16.8.0", @@ -2554,9 +2557,10 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", - "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" }, "node_modules/@happysanta/router": { "version": "0.3.1", @@ -4024,11 +4028,12 @@ } }, "node_modules/@swc/helpers": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz", - "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==", + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", + "license": "Apache-2.0", "dependencies": { - "tslib": "^2.4.0" + "tslib": "^2.8.0" } }, "node_modules/@telegram-apps/sdk": { @@ -5352,27 +5357,38 @@ } }, "node_modules/@vkontakte/vkjs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@vkontakte/vkjs/-/vkjs-1.1.1.tgz", - "integrity": "sha512-+tOfx6M+tsHweG+2xEHUUA5SAWbA2dYYX8Owa6uQ8OpwDq6LCgGikCas2SWDA61N5IXerfbfhDaKwFTuoG2vMg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@vkontakte/vkjs/-/vkjs-1.3.0.tgz", + "integrity": "sha512-GfwCC2JNetiiFZcEWyK9LOy8PHUKK2+L8VSJMbXKnpi4LnkxXYMEBsun1rEKGliPITYZC50nLm7jhxbCgcxVuw==", + "license": "MIT", "dependencies": { - "@swc/helpers": "^0.5.0" + "@swc/helpers": "^0.5.0", + "clsx": "^2.1.1" }, "engines": { "yarn": "^1.21.1" } }, + "node_modules/@vkontakte/vkjs/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/@vkontakte/vkui": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@vkontakte/vkui/-/vkui-6.0.2.tgz", - "integrity": "sha512-Wnar49W7iUMANz4nK1c/uM+FayqKsYXPF2NAfxv/EvJrnDAVd5Ryv7zIX/+zo1LX7+MomkWPAjjlG9wRdFjbSQ==", + "version": "6.7.4", + "resolved": "https://registry.npmjs.org/@vkontakte/vkui/-/vkui-6.7.4.tgz", + "integrity": "sha512-EUpL2k8+veOIkSJw4gDspZ6DQIgXO2PgfwIzpaT8E4zP90j2JcHz1LB91sPyveuAn4AzCmnqHD1pIyAZXbEIkw==", + "license": "MIT", "dependencies": { - "@swc/helpers": "^0.5.3", - "@vkontakte/icons": "^2.62.0", - "@vkontakte/vkjs": "^1.1.1", - "@vkontakte/vkui-floating-ui": "^0.1.2", - "dayjs": "^1.11.10", - "mitt": "^3.0.1" + "@swc/helpers": "^0.5.13", + "@vkontakte/icons": "^2.115.0", + "@vkontakte/vkjs": "^1.3.0", + "@vkontakte/vkui-floating-ui": "^0.2.1", + "date-fns": "^3.6.0" }, "peerDependencies": { "react": "^18.2.0", @@ -5380,18 +5396,43 @@ } }, "node_modules/@vkontakte/vkui-floating-ui": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@vkontakte/vkui-floating-ui/-/vkui-floating-ui-0.1.5.tgz", - "integrity": "sha512-5BJOI3/K+aDMdhpvftbvaAlpXktU9fPkYpG5cOQDKTZ9uissWOc0Kk350vInPWIsH9nlovjswKtVmKl0/fA/mQ==", + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@vkontakte/vkui-floating-ui/-/vkui-floating-ui-0.2.7.tgz", + "integrity": "sha512-4cHwX2pJI4HBZM+Cp/E4f9tDIxU6AimvDEX5WEHGOLUkbCZDiSB2wavsZz128czedpmA/b+AX/l2codwKOhJtA==", + "license": "MIT", "dependencies": { - "@floating-ui/react-dom": "^2.0.8", - "@swc/helpers": "^0.5.3" + "@floating-ui/react-dom": "^2.1.6", + "@swc/helpers": "^0.5.17" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, + "node_modules/@vkontakte/vkui/node_modules/@vkontakte/icons": { + "version": "2.170.0", + "resolved": "https://registry.npmjs.org/@vkontakte/icons/-/icons-2.170.0.tgz", + "integrity": "sha512-AKGNJ1t99QrPg9BitcWdJ0H4OOHmXAwUWyVDTaR6csf05gYehCltrIyLd80waCzOvUQGi9q/BXgOg0oWTJSGcQ==", + "license": "MIT", + "dependencies": { + "@vkontakte/icons-sprite": "2.3.1" + }, + "peerDependencies": { + "react": "^16.9.34 || ^17 || ^18" + } + }, + "node_modules/@vkontakte/vkui/node_modules/@vkontakte/icons-sprite": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@vkontakte/icons-sprite/-/icons-sprite-2.3.1.tgz", + "integrity": "sha512-j7HB2Mqw2kJdWN/sTgiXDW7hXpsIM6l5MYYJ9OisxtzbitXH1wvl7aEXUc3NuR0JPVg7ImaZeot+HU4VjtMcag==", + "license": "MIT", + "dependencies": { + "@swc/helpers": "^0.5.15" + }, + "peerDependencies": { + "react": "^16.9.34 || ^17 || ^18" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.1", "dev": true, @@ -8892,10 +8933,15 @@ "node": ">=10" } }, - "node_modules/dayjs": { - "version": "1.11.10", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", - "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" + "node_modules/date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } }, "node_modules/debug": { "version": "4.3.4", @@ -15021,11 +15067,6 @@ "version": "1.2.6", "license": "MIT" }, - "node_modules/mitt": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", - "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==" - }, "node_modules/mj-context-menu": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz", @@ -19811,7 +19852,9 @@ } }, "node_modules/tslib": { - "version": "2.4.0", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/tsutils": { @@ -22624,34 +22667,34 @@ "integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==" }, "@floating-ui/core": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz", - "integrity": "sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", "requires": { - "@floating-ui/utils": "^0.2.1" + "@floating-ui/utils": "^0.2.10" } }, "@floating-ui/dom": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.3.tgz", - "integrity": "sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", "requires": { - "@floating-ui/core": "^1.0.0", - "@floating-ui/utils": "^0.2.0" + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" } }, "@floating-ui/react-dom": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.8.tgz", - "integrity": "sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", + "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", "requires": { - "@floating-ui/dom": "^1.6.1" + "@floating-ui/dom": "^1.7.4" } }, "@floating-ui/utils": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", - "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==" }, "@happysanta/router": { "version": "0.3.1", @@ -23607,11 +23650,11 @@ } }, "@swc/helpers": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz", - "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==", + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", "requires": { - "tslib": "^2.4.0" + "tslib": "^2.8.0" } }, "@telegram-apps/sdk": { @@ -24502,33 +24545,58 @@ } }, "@vkontakte/vkjs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@vkontakte/vkjs/-/vkjs-1.1.1.tgz", - "integrity": "sha512-+tOfx6M+tsHweG+2xEHUUA5SAWbA2dYYX8Owa6uQ8OpwDq6LCgGikCas2SWDA61N5IXerfbfhDaKwFTuoG2vMg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@vkontakte/vkjs/-/vkjs-1.3.0.tgz", + "integrity": "sha512-GfwCC2JNetiiFZcEWyK9LOy8PHUKK2+L8VSJMbXKnpi4LnkxXYMEBsun1rEKGliPITYZC50nLm7jhxbCgcxVuw==", "requires": { - "@swc/helpers": "^0.5.0" + "@swc/helpers": "^0.5.0", + "clsx": "^2.1.1" + }, + "dependencies": { + "clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==" + } } }, "@vkontakte/vkui": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@vkontakte/vkui/-/vkui-6.0.2.tgz", - "integrity": "sha512-Wnar49W7iUMANz4nK1c/uM+FayqKsYXPF2NAfxv/EvJrnDAVd5Ryv7zIX/+zo1LX7+MomkWPAjjlG9wRdFjbSQ==", + "version": "6.7.4", + "resolved": "https://registry.npmjs.org/@vkontakte/vkui/-/vkui-6.7.4.tgz", + "integrity": "sha512-EUpL2k8+veOIkSJw4gDspZ6DQIgXO2PgfwIzpaT8E4zP90j2JcHz1LB91sPyveuAn4AzCmnqHD1pIyAZXbEIkw==", "requires": { - "@swc/helpers": "^0.5.3", - "@vkontakte/icons": "^2.62.0", - "@vkontakte/vkjs": "^1.1.1", - "@vkontakte/vkui-floating-ui": "^0.1.2", - "dayjs": "^1.11.10", - "mitt": "^3.0.1" + "@swc/helpers": "^0.5.13", + "@vkontakte/icons": "^2.115.0", + "@vkontakte/vkjs": "^1.3.0", + "@vkontakte/vkui-floating-ui": "^0.2.1", + "date-fns": "^3.6.0" + }, + "dependencies": { + "@vkontakte/icons": { + "version": "2.170.0", + "resolved": "https://registry.npmjs.org/@vkontakte/icons/-/icons-2.170.0.tgz", + "integrity": "sha512-AKGNJ1t99QrPg9BitcWdJ0H4OOHmXAwUWyVDTaR6csf05gYehCltrIyLd80waCzOvUQGi9q/BXgOg0oWTJSGcQ==", + "requires": { + "@vkontakte/icons-sprite": "2.3.1" + } + }, + "@vkontakte/icons-sprite": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@vkontakte/icons-sprite/-/icons-sprite-2.3.1.tgz", + "integrity": "sha512-j7HB2Mqw2kJdWN/sTgiXDW7hXpsIM6l5MYYJ9OisxtzbitXH1wvl7aEXUc3NuR0JPVg7ImaZeot+HU4VjtMcag==", + "requires": { + "@swc/helpers": "^0.5.15" + } + } } }, "@vkontakte/vkui-floating-ui": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@vkontakte/vkui-floating-ui/-/vkui-floating-ui-0.1.5.tgz", - "integrity": "sha512-5BJOI3/K+aDMdhpvftbvaAlpXktU9fPkYpG5cOQDKTZ9uissWOc0Kk350vInPWIsH9nlovjswKtVmKl0/fA/mQ==", + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@vkontakte/vkui-floating-ui/-/vkui-floating-ui-0.2.7.tgz", + "integrity": "sha512-4cHwX2pJI4HBZM+Cp/E4f9tDIxU6AimvDEX5WEHGOLUkbCZDiSB2wavsZz128czedpmA/b+AX/l2codwKOhJtA==", "requires": { - "@floating-ui/react-dom": "^2.0.8", - "@swc/helpers": "^0.5.3" + "@floating-ui/react-dom": "^2.1.6", + "@swc/helpers": "^0.5.17" } }, "@webassemblyjs/ast": { @@ -26936,10 +27004,10 @@ } } }, - "dayjs": { - "version": "1.11.10", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", - "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" + "date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==" }, "debug": { "version": "4.3.4", @@ -30930,11 +30998,6 @@ "minimist": { "version": "1.2.6" }, - "mitt": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", - "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==" - }, "mj-context-menu": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz", @@ -33867,7 +33930,9 @@ } }, "tslib": { - "version": "2.4.0" + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" }, "tsutils": { "version": "3.21.0", diff --git a/GPTutor-Frontend/package.json b/GPTutor-Frontend/package.json index 6f051c44..095e3477 100644 --- a/GPTutor-Frontend/package.json +++ b/GPTutor-Frontend/package.json @@ -29,7 +29,7 @@ "@vkontakte/vk-bridge": "^2.14.1", "@vkontakte/vk-bridge-react": "^1.0.1", "@vkontakte/vk-miniapps-deploy": "0.0.25", - "@vkontakte/vkui": "6.0.2", + "@vkontakte/vkui": "6.7.4", "babel-eslint": "^10.1.0", "cross-env": "7.0.3", "dignals": "0.1.0", From 44d0b68075206e0efd84ccf47eafdef111b3c52a Mon Sep 17 00:00:00 2001 From: Grigoriy Gavrilov Date: Sun, 21 Sep 2025 20:05:22 +0300 Subject: [PATCH 003/109] =?UTF-8?q?=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D1=86=D0=B0=20=D0=B2=D0=BE=D0=BF=D1=80=D0=BE=D1=81=D1=8B=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D0=B4=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=B0=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- GPTutor-Frontend/src/App.tsx | 2 ++ .../src/entity/routing/routing.ts | 4 +++ GPTutor-Frontend/src/index.tsx | 1 + .../src/panels/DocQuestionPanel/index.tsx | 30 +++++++++++++++++++ GPTutor-Frontend/src/services/AppService.ts | 11 +++++-- 5 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 GPTutor-Frontend/src/panels/DocQuestionPanel/index.tsx diff --git a/GPTutor-Frontend/src/App.tsx b/GPTutor-Frontend/src/App.tsx index f7bc2896..9b5e254c 100644 --- a/GPTutor-Frontend/src/App.tsx +++ b/GPTutor-Frontend/src/App.tsx @@ -75,6 +75,7 @@ import { BingPanel } from "$/panels/BingPanel"; import VKDocQuestionPanel from "./panels/VKDocQuestionPanel/VKDocQestionPanel"; import { VkDocQuestionRequest } from "$/panels/VkDocQuestionRequest"; import { retrieveLaunchParams } from "@telegram-apps/sdk"; +import DocQuestionPanel from "$/panels/DocQuestionPanel"; const App = () => { const location = useLocation(); @@ -198,6 +199,7 @@ const App = () => { + )} diff --git a/GPTutor-Frontend/src/entity/routing/routing.ts b/GPTutor-Frontend/src/entity/routing/routing.ts index 063963dd..6fd719f9 100644 --- a/GPTutor-Frontend/src/entity/routing/routing.ts +++ b/GPTutor-Frontend/src/entity/routing/routing.ts @@ -41,6 +41,8 @@ export enum RoutingPages { vkDocQuestionPanel = "/vk-doc-question-panel", vkDocQuestionRequest = "/vk-doc-question-request", + + docQuestion = "/doc-question", } export enum Views { @@ -89,6 +91,8 @@ export enum Panels { vkDocQuestionPanel = "vk-doc-question-panel", vkDocQuestionRequest = "vk-doc-question-request", + + docQuestion = "doc-question", } export enum Modals { diff --git a/GPTutor-Frontend/src/index.tsx b/GPTutor-Frontend/src/index.tsx index 6da3fb41..1eb35449 100644 --- a/GPTutor-Frontend/src/index.tsx +++ b/GPTutor-Frontend/src/index.tsx @@ -128,6 +128,7 @@ const routes = { Panels.vkDocQuestionRequest, Views.viewMain ), + [RoutingPages.docQuestion]: new Page(Panels.docQuestion, Views.viewMain), }; const router = new Router(routes); diff --git a/GPTutor-Frontend/src/panels/DocQuestionPanel/index.tsx b/GPTutor-Frontend/src/panels/DocQuestionPanel/index.tsx new file mode 100644 index 00000000..c554426c --- /dev/null +++ b/GPTutor-Frontend/src/panels/DocQuestionPanel/index.tsx @@ -0,0 +1,30 @@ +import * as React from "react"; +import { Div, Panel, PanelHeader, PanelHeaderBack } from "@vkontakte/vkui"; +import { AppContainer } from "$/components/AppContainer"; +import { useNavigationContext } from "$/NavigationContext"; +import PanelTitle from "$/components/PanelTitle"; + +interface IProps { + id: string; +} + +function DocQuestionPanel({ id }: IProps) { + const { goBack } = useNavigationContext(); + + return ( + + }> + + + } + > +
chlen
+
+
+ ); +} + +export default DocQuestionPanel; diff --git a/GPTutor-Frontend/src/services/AppService.ts b/GPTutor-Frontend/src/services/AppService.ts index 84caa7e1..88b576e7 100644 --- a/GPTutor-Frontend/src/services/AppService.ts +++ b/GPTutor-Frontend/src/services/AppService.ts @@ -6,10 +6,9 @@ export enum AppInstanceType { GPTutor = "GPTutor", AiHumor = "AiHumor", SmartVkDoc = "SmartVkDoc", + DocQuestion = "DocQuestion", } -console.log(window); - class AppService { loading = sig(true); @@ -36,6 +35,10 @@ class AppService { return this.appInstance === AppInstanceType.GPTutor; } + isDocQuestion() { + return this.appInstance === AppInstanceType.DocQuestion; + } + isAiHumor() { return this.appInstance === AppInstanceType.AiHumor; } @@ -61,6 +64,10 @@ class AppService { return RoutingPages.vkDocQuestionPanel; } + if (this.isDocQuestion()) { + return RoutingPages.docQuestion; + } + return RoutingPages.mainAnecdote; } From da3f14dbdc2cf7a9db7d374ed746606c0adac2e7 Mon Sep 17 00:00:00 2001 From: Grigoriy Gavrilov Date: Mon, 29 Sep 2025 11:04:01 +0300 Subject: [PATCH 004/109] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=BE=D0=BD=D0=B0?= =?UTF-8?q?=D0=BB=20=D0=BF=D0=BE=20=D0=BF=D1=80=D0=BE=D0=B4=D0=B0=D0=B6?= =?UTF-8?q?=D0=B5=20=D0=B0=D0=BF=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- GPTutor-Backend-v2/.dockerignore | 12 + GPTutor-Backend-v2/README.md | 105 + .../docs/CHAT_COMPLETIONS_API.md | 459 + GPTutor-Backend-v2/docs/MODELS_API.md | 99 + GPTutor-Backend-v2/docs/QUICK_START.md | 160 + GPTutor-Backend-v2/docs/RATE_LIMITING.md | 180 + GPTutor-Backend-v2/docs/README-internal.md | 163 + GPTutor-Backend-v2/docs/README.md | 152 + GPTutor-Backend-v2/docs/USER_GUIDE.md | 97 + GPTutor-Backend-v2/docs/dark.html | 143 + GPTutor-Backend-v2/docs/index.html | 184 + GPTutor-Backend-v2/docs/internal-api.yaml | 985 +++ GPTutor-Backend-v2/docs/internal.html | 276 + GPTutor-Backend-v2/docs/openapi.yaml | 1201 +++ GPTutor-Backend-v2/docs/package-lock.json | 1212 +++ GPTutor-Backend-v2/docs/package.json | 32 + GPTutor-Backend-v2/docs/serve-internal.js | 79 + GPTutor-Backend-v2/docs/serve.js | 84 + GPTutor-Backend-v2/logs/.gitignore | 8 + GPTutor-Backend-v2/nodemon.json | 7 + GPTutor-Backend-v2/package-lock.json | 3042 +++++++ GPTutor-Backend-v2/package.json | 60 + GPTutor-Backend-v2/prisma/dev.db | Bin 0 -> 36864 bytes GPTutor-Backend-v2/prisma/schema.prisma | 45 + .../scripts/test-rate-limits.js | 136 + .../src/config/rateLimitConfig.ts | 47 + .../src/controllers/AuthController.ts | 98 + .../src/controllers/BaseController.ts | 74 + .../src/controllers/CompletionController.ts | 353 + .../src/controllers/FilesController.ts | 129 + .../src/controllers/HealthController.ts | 22 + .../src/controllers/ModelsController.ts | 148 + GPTutor-Backend-v2/src/controllers/index.ts | 54 + GPTutor-Backend-v2/src/index.ts | 189 + .../src/middleware/authMiddleware.ts | 41 + .../src/middleware/loggingMiddleware.ts | 64 + .../middleware/rateLimitMiddleware.test.ts | 76 + .../src/middleware/rateLimitMiddleware.ts | 127 + .../src/repositories/FileRepository.ts | 102 + .../src/repositories/UserRepository.ts | 80 + .../src/services/AuthService.ts | 46 + .../src/services/FilesService.ts | 179 + .../src/services/LLMCostEvaluate.ts | 188 + .../src/services/LoggerService.ts | 272 + .../src/services/OpenRouterService.ts | 65 + GPTutor-Backend-v2/src/types/openrouter.ts | 68 + GPTutor-Backend-v2/src/utils/vkAuth.ts | 131 + GPTutor-Backend-v2/tsconfig.json | 22 + GPTutor-Frontend-v2/.eslintrc.cjs | 15 + GPTutor-Frontend-v2/README.md | 55 + GPTutor-Frontend-v2/index.html | 16 + GPTutor-Frontend-v2/package-lock.json | 7433 +++++++++++++++++ GPTutor-Frontend-v2/package.json | 41 + GPTutor-Frontend-v2/public/logo.svg | 9 + GPTutor-Frontend-v2/src/App.tsx | 32 + GPTutor-Frontend-v2/src/AppConfig.tsx | 41 + GPTutor-Frontend-v2/src/assets/persik.png | Bin 0 -> 11033 bytes GPTutor-Frontend-v2/src/eruda.ts | 5 + GPTutor-Frontend-v2/src/main.tsx | 11 + GPTutor-Frontend-v2/src/panels/Home.tsx | 298 + GPTutor-Frontend-v2/src/panels/Persik.tsx | 19 + GPTutor-Frontend-v2/src/panels/index.ts | 4 + GPTutor-Frontend-v2/src/routes.ts | 27 + GPTutor-Frontend-v2/src/utils/index.ts | 1 + .../src/utils/transformVKBridgeAdaptivity.ts | 31 + GPTutor-Frontend-v2/src/vite-env.d.ts | 1 + GPTutor-Frontend-v2/tsconfig.json | 27 + GPTutor-Frontend-v2/tsconfig.node.json | 12 + GPTutor-Frontend-v2/vite.config.ts | 38 + GPTutor-Frontend-v2/vk-hosting-config.json | 9 + GPTutor-Frontend/package-lock.json | 373 +- GPTutor-Frontend/package.json | 4 +- GPTutor-Frontend/src/App.tsx | 10 +- .../components/AppContainer/AppContainer.tsx | 1 - GPTutor-Frontend/src/index.tsx | 18 +- .../panels/ApiLLMPanel/ApiLLMPanel.module.css | 370 + .../src/panels/ApiLLMPanel/index.tsx | 801 ++ .../src/panels/DocQuestionPanel/index.tsx | 30 - GPTutor-Frontend/src/services/AppService.ts | 8 +- 79 files changed, 21051 insertions(+), 185 deletions(-) create mode 100644 GPTutor-Backend-v2/.dockerignore create mode 100644 GPTutor-Backend-v2/README.md create mode 100644 GPTutor-Backend-v2/docs/CHAT_COMPLETIONS_API.md create mode 100644 GPTutor-Backend-v2/docs/MODELS_API.md create mode 100644 GPTutor-Backend-v2/docs/QUICK_START.md create mode 100644 GPTutor-Backend-v2/docs/RATE_LIMITING.md create mode 100644 GPTutor-Backend-v2/docs/README-internal.md create mode 100644 GPTutor-Backend-v2/docs/README.md create mode 100644 GPTutor-Backend-v2/docs/USER_GUIDE.md create mode 100644 GPTutor-Backend-v2/docs/dark.html create mode 100644 GPTutor-Backend-v2/docs/index.html create mode 100644 GPTutor-Backend-v2/docs/internal-api.yaml create mode 100644 GPTutor-Backend-v2/docs/internal.html create mode 100644 GPTutor-Backend-v2/docs/openapi.yaml create mode 100644 GPTutor-Backend-v2/docs/package-lock.json create mode 100644 GPTutor-Backend-v2/docs/package.json create mode 100644 GPTutor-Backend-v2/docs/serve-internal.js create mode 100644 GPTutor-Backend-v2/docs/serve.js create mode 100644 GPTutor-Backend-v2/logs/.gitignore create mode 100644 GPTutor-Backend-v2/nodemon.json create mode 100644 GPTutor-Backend-v2/package-lock.json create mode 100644 GPTutor-Backend-v2/package.json create mode 100644 GPTutor-Backend-v2/prisma/dev.db create mode 100644 GPTutor-Backend-v2/prisma/schema.prisma create mode 100644 GPTutor-Backend-v2/scripts/test-rate-limits.js create mode 100644 GPTutor-Backend-v2/src/config/rateLimitConfig.ts create mode 100644 GPTutor-Backend-v2/src/controllers/AuthController.ts create mode 100644 GPTutor-Backend-v2/src/controllers/BaseController.ts create mode 100644 GPTutor-Backend-v2/src/controllers/CompletionController.ts create mode 100644 GPTutor-Backend-v2/src/controllers/FilesController.ts create mode 100644 GPTutor-Backend-v2/src/controllers/HealthController.ts create mode 100644 GPTutor-Backend-v2/src/controllers/ModelsController.ts create mode 100644 GPTutor-Backend-v2/src/controllers/index.ts create mode 100644 GPTutor-Backend-v2/src/index.ts create mode 100644 GPTutor-Backend-v2/src/middleware/authMiddleware.ts create mode 100644 GPTutor-Backend-v2/src/middleware/loggingMiddleware.ts create mode 100644 GPTutor-Backend-v2/src/middleware/rateLimitMiddleware.test.ts create mode 100644 GPTutor-Backend-v2/src/middleware/rateLimitMiddleware.ts create mode 100644 GPTutor-Backend-v2/src/repositories/FileRepository.ts create mode 100644 GPTutor-Backend-v2/src/repositories/UserRepository.ts create mode 100644 GPTutor-Backend-v2/src/services/AuthService.ts create mode 100644 GPTutor-Backend-v2/src/services/FilesService.ts create mode 100644 GPTutor-Backend-v2/src/services/LLMCostEvaluate.ts create mode 100644 GPTutor-Backend-v2/src/services/LoggerService.ts create mode 100644 GPTutor-Backend-v2/src/services/OpenRouterService.ts create mode 100644 GPTutor-Backend-v2/src/types/openrouter.ts create mode 100644 GPTutor-Backend-v2/src/utils/vkAuth.ts create mode 100644 GPTutor-Backend-v2/tsconfig.json create mode 100644 GPTutor-Frontend-v2/.eslintrc.cjs create mode 100644 GPTutor-Frontend-v2/README.md create mode 100644 GPTutor-Frontend-v2/index.html create mode 100644 GPTutor-Frontend-v2/package-lock.json create mode 100644 GPTutor-Frontend-v2/package.json create mode 100644 GPTutor-Frontend-v2/public/logo.svg create mode 100644 GPTutor-Frontend-v2/src/App.tsx create mode 100644 GPTutor-Frontend-v2/src/AppConfig.tsx create mode 100644 GPTutor-Frontend-v2/src/assets/persik.png create mode 100644 GPTutor-Frontend-v2/src/eruda.ts create mode 100644 GPTutor-Frontend-v2/src/main.tsx create mode 100644 GPTutor-Frontend-v2/src/panels/Home.tsx create mode 100644 GPTutor-Frontend-v2/src/panels/Persik.tsx create mode 100644 GPTutor-Frontend-v2/src/panels/index.ts create mode 100644 GPTutor-Frontend-v2/src/routes.ts create mode 100644 GPTutor-Frontend-v2/src/utils/index.ts create mode 100644 GPTutor-Frontend-v2/src/utils/transformVKBridgeAdaptivity.ts create mode 100644 GPTutor-Frontend-v2/src/vite-env.d.ts create mode 100644 GPTutor-Frontend-v2/tsconfig.json create mode 100644 GPTutor-Frontend-v2/tsconfig.node.json create mode 100644 GPTutor-Frontend-v2/vite.config.ts create mode 100644 GPTutor-Frontend-v2/vk-hosting-config.json create mode 100644 GPTutor-Frontend/src/panels/ApiLLMPanel/ApiLLMPanel.module.css create mode 100644 GPTutor-Frontend/src/panels/ApiLLMPanel/index.tsx delete mode 100644 GPTutor-Frontend/src/panels/DocQuestionPanel/index.tsx diff --git a/GPTutor-Backend-v2/.dockerignore b/GPTutor-Backend-v2/.dockerignore new file mode 100644 index 00000000..7f72dd54 --- /dev/null +++ b/GPTutor-Backend-v2/.dockerignore @@ -0,0 +1,12 @@ +node_modules +npm-debug.log +.git +.gitignore +README.md +.env +.nyc_output +coverage +.coverage +dist +*.db + diff --git a/GPTutor-Backend-v2/README.md b/GPTutor-Backend-v2/README.md new file mode 100644 index 00000000..2f443385 --- /dev/null +++ b/GPTutor-Backend-v2/README.md @@ -0,0 +1,105 @@ +# GPTutor Backend v2 + +Простой и быстрый бэкенд на Fastify с SQLite и Prisma ORM. + +## Особенности + +- 🚀 **Fastify** - быстрый веб-фреймворк +- 🗃️ **SQLite** - легковесная база данных +- 🔧 **Prisma** - современная ORM +- 📦 **TypeScript** - типизированный JavaScript +- 🐳 **Docker** - контейнеризация + +## Структура базы данных + +Одна простая таблица `users`: +- `id` - уникальный идентификатор +- `email` - email пользователя (опционально) +- `username` - имя пользователя (опционально) +- `vkId` - VK ID пользователя (опционально) +- `balance` - баланс пользователя +- `apiKey` - уникальный API ключ +- `isActive` - активен ли пользователь +- `createdAt` / `updatedAt` - временные метки + +## API Endpoints + +### Users +- `GET /users` - получить всех пользователей +- `GET /users/:id` - получить пользователя по ID +- `GET /users/by-api-key/:apiKey` - получить пользователя по API ключу +- `POST /users` - создать пользователя +- `PATCH /users/:id/balance` - обновить баланс +- `PATCH /users/:id/add-balance` - добавить к балансу +- `PATCH /users/:id/regenerate-api-key` - сгенерировать новый API ключ +- `DELETE /users/:id` - удалить пользователя + +### Health +- `GET /health` - проверка состояния сервера + +## Быстрый старт + +### Локальная разработка + +```bash +# Установить зависимости +npm install + +# Настроить базу данных +npm run db:push + +# Запустить в режиме разработки +npm run dev +``` + +### Продакшн + +```bash +# Собрать проект +npm run build + +# Запустить +npm start +``` + +### Docker + +```bash +# Собрать образ +docker build -t gptutor-backend-v2 . + +# Запустить контейнер +docker run -p 3001:3001 gptutor-backend-v2 +``` + +## Переменные окружения + +```env +DATABASE_URL="file:./dev.db" +PORT=3001 +NODE_ENV=development +``` + +## Примеры использования + +### Создать пользователя +```bash +curl -X POST http://localhost:3001/users \ + -H "Content-Type: application/json" \ + -d '{"email": "user@example.com", "username": "testuser", "balance": 100}' +``` + +### Получить пользователя по API ключу +```bash +curl http://localhost:3001/users/by-api-key/YOUR_API_KEY +``` + +### Добавить баланс +```bash +curl -X PATCH http://localhost:3001/users/USER_ID/add-balance \ + -H "Content-Type: application/json" \ + -d '{"amount": 50}' +``` + + + diff --git a/GPTutor-Backend-v2/docs/CHAT_COMPLETIONS_API.md b/GPTutor-Backend-v2/docs/CHAT_COMPLETIONS_API.md new file mode 100644 index 00000000..d02b0659 --- /dev/null +++ b/GPTutor-Backend-v2/docs/CHAT_COMPLETIONS_API.md @@ -0,0 +1,459 @@ +# Chat Completions API - Подробная документация + +## Обзор + +Endpoint `/v1/chat/completions` предоставляет OpenAI-совместимый API для создания chat completions с использованием различных языковых моделей через OpenRouter. + +**URL:** `POST /v1/chat/completions` +**Тип контента:** `application/json` +**Авторизация:** Bearer токен (API ключ пользователя) + +--- + +## 🔐 Аутентификация + +### API Key +```http +Authorization: Bearer sk-user-abc123def456... +``` + +**Как получить API ключ:** +1. Авторизуйтесь через VK Mini App +2. Вызовите `GET /vk-test` с VK токеном +3. В ответе получите `dbUser.apiKey` + +### Валидация +- ✅ API ключ должен существовать в базе данных +- ✅ Пользователь должен быть активным (`isActive: true`) +- ✅ На балансе должно быть достаточно средств + +--- + +## 📋 Параметры запроса + +### Обязательные параметры + +| Параметр | Тип | Описание | +|----------|-----|----------| +| `messages` | `Array` | Массив сообщений диалога | + +### Опциональные параметры + +| Параметр | Тип | По умолчанию | Описание | +|----------|-----|--------------|----------| +| `model` | `string` | `"google/gemini-2.5-flash-lite"` | Модель для генерации | +| `max_tokens` | `integer` | - | Максимальное количество токенов в ответе | +| `temperature` | `float` | - | Креативность (0.0-2.0) | +| `top_p` | `float` | - | Nucleus sampling (0.0-1.0) | +| `frequency_penalty` | `float` | - | Штраф за повторение слов (-2.0 до 2.0) | +| `presence_penalty` | `float` | - | Штраф за повторение тем (-2.0 до 2.0) | +| `stop` | `Array` | - | Стоп-последовательности | +| `stream` | `boolean` | `false` | Включить streaming режим | + +### Структура Message + +```typescript +interface Message { + role: "system" | "user" | "assistant"; + content: string; +} +``` + +**Роли:** +- `system` - Системные инструкции для AI +- `user` - Сообщения пользователя +- `assistant` - Ответы AI (для контекста) + +--- + +## 🤖 Поддерживаемые модели + +### Рекомендуемые модели + +| Модель | Провайдер | Описание | Стоимость | +|--------|-----------|----------|-----------| +| `google/gemini-2.5-flash-lite` | Google | Быстрая и дешевая (по умолчанию) | ~$0.01/1K токенов | +| `anthropic/claude-3-haiku` | Anthropic | Сбалансированная | ~$0.25/1K токенов | +| `openai/gpt-4o-mini` | OpenAI | Компактная GPT-4 | ~$0.15/1K токенов | +| `meta-llama/llama-3.1-8b-instruct` | Meta | Open source | ~$0.06/1K токенов | + +### Все доступные модели +Полный список доступен через OpenRouter API. Система поддерживает **326 моделей**. + +--- + +## 💰 Стоимость и биллинг + +### Расчет стоимости +1. OpenRouter возвращает стоимость в долларах +2. GPTutor конвертирует в рубли (курс: **90₽ за $1**) +3. Стоимость автоматически списывается с баланса + +### Информация о стоимости в ответе +```json +{ + "usage": { + "cost_details": { + "upstream_inference_completions_cost": 0.45 + } + } +} +``` + +### Проверка баланса +- Баланс проверяется перед запросом +- При недостатке средств возвращается ошибка `402 Payment Required` + +--- + +## 📤 Примеры запросов + +### Простой запрос +```bash +curl -X POST http://localhost:3001/v1/chat/completions \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer sk-user-abc123..." \ + -d '{ + "messages": [ + {"role": "user", "content": "Привет! Как дела?"} + ] + }' +``` + +### Запрос с системной инструкцией +```bash +curl -X POST http://localhost:3001/v1/chat/completions \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer sk-user-abc123..." \ + -d '{ + "model": "anthropic/claude-3-haiku", + "messages": [ + {"role": "system", "content": "Ты полезный AI ассистент, отвечающий кратко и по делу."}, + {"role": "user", "content": "Объясни что такое API"} + ], + "max_tokens": 200, + "temperature": 0.7 + }' +``` + +### Streaming запрос +```bash +curl -X POST http://localhost:3001/v1/chat/completions \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer sk-user-abc123..." \ + -d '{ + "messages": [ + {"role": "user", "content": "Расскажи длинную историю"} + ], + "stream": true, + "max_tokens": 500 + }' +``` + +--- + +## 📥 Форматы ответов + +### Non-streaming ответ (обычный) +```json +{ + "id": "chatcmpl-abc123", + "object": "chat.completion", + "created": 1677652288, + "model": "google/gemini-2.5-flash-lite", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "Привет! У меня всё отлично, спасибо что спросил! Как дела у тебя?" + }, + "finish_reason": "stop" + } + ], + "usage": { + "prompt_tokens": 12, + "completion_tokens": 24, + "total_tokens": 36, + "cost_details": { + "upstream_inference_completions_cost": 0.45 + } + } +} +``` + +### Streaming ответ (Server-Sent Events) +``` +Content-Type: text/event-stream + +data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1677652288,"model":"google/gemini-2.5-flash-lite","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]} + +data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1677652288,"model":"google/gemini-2.5-flash-lite","choices":[{"index":0,"delta":{"content":"Привет"},"finish_reason":null}]} + +data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1677652288,"model":"google/gemini-2.5-flash-lite","choices":[{"index":0,"delta":{"content":"!"},"finish_reason":null}]} + +data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1677652288,"model":"google/gemini-2.5-flash-lite","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]} + +data: [DONE] +``` + +--- + +## ⚠️ Коды ошибок + +### 400 Bad Request - Ошибка валидации +```json +{ + "error": "messages array is required" +} +``` + +**Причины:** +- Отсутствует параметр `messages` +- `messages` не является массивом +- Пустой массив `messages` + +### 401 Unauthorized - Ошибка авторизации +```json +{ + "error": "Invalid API key or inactive user" +} +``` + +**Причины:** +- Отсутствует заголовок `Authorization` +- Неверный формат токена (не `Bearer ...`) +- API ключ не найден в базе данных +- Пользователь неактивен + +### 402 Payment Required - Недостаток средств +```json +{ + "error": "Insufficient balance" +} +``` + +**Причины:** +- На балансе пользователя недостаточно средств +- Предварительная оценка стоимости превышает баланс + +### 500 Internal Server Error - Серверная ошибка +```json +{ + "error": "Internal server error" +} +``` + +**Причины:** +- Ошибка OpenRouter API +- Ошибка базы данных +- Неожиданная системная ошибка + +--- + +## 🔄 Streaming режим + +### Особенности +- Ответ приходит в режиме реального времени +- Использует Server-Sent Events (SSE) +- Каждый chunk содержит часть ответа +- Завершается сообщением `data: [DONE]` + +### Обработка в JavaScript +```javascript +const response = await fetch('/v1/chat/completions', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer sk-user-...' + }, + body: JSON.stringify({ + messages: [{"role": "user", "content": "Привет!"}], + stream: true + }) +}); + +const reader = response.body.getReader(); +const decoder = new TextDecoder(); + +while (true) { + const { done, value } = await reader.read(); + if (done) break; + + const chunk = decoder.decode(value); + const lines = chunk.split('\n'); + + for (const line of lines) { + if (line.startsWith('data: ')) { + const data = line.slice(6); + if (data === '[DONE]') return; + + try { + const parsed = JSON.parse(data); + const content = parsed.choices[0]?.delta?.content; + if (content) { + console.log(content); // Выводим каждую часть ответа + } + } catch (e) { + // Игнорируем ошибки парсинга + } + } + } +} +``` + +--- + +## 📊 Логгирование и мониторинг + +### Автоматическое логгирование +Система автоматически логгирует: +- ✅ Входящие запросы с параметрами +- ✅ Время выполнения +- ✅ Использованную модель +- ✅ Количество токенов +- ✅ Стоимость в рублях +- ✅ Ошибки и их причины + +### Пример логов +```json +{ + "timestamp": "2024-09-28 10:30:15", + "level": "info", + "message": "LLM Request: google/gemini-2.5-flash-lite", + "type": "llm", + "model": "google/gemini-2.5-flash-lite", + "userId": "123", + "requestId": "abc-123-def", + "stream": false, + "messagesCount": 2 +} +``` + +--- + +## 🔧 Технические детали + +### Внутренняя архитектура +1. **Валидация** - проверка API ключа и параметров +2. **Авторизация** - поиск пользователя в базе данных +3. **Подготовка** - формирование параметров для OpenRouter +4. **Выполнение** - вызов OpenRouter API +5. **Обработка** - расчет стоимости и списание с баланса +6. **Ответ** - возврат результата клиенту + +### Используемые сервисы +- **OpenRouterService** - интеграция с OpenRouter API +- **LLMCostEvaluate** - расчет стоимости в рублях +- **UserRepository** - работа с пользователями +- **LoggerService** - структурированное логгирование + +### Производительность +- Среднее время ответа: **1-3 секунды** +- Поддержка concurrent запросов +- Автоматический retry для временных ошибок +- Graceful handling ошибок OpenRouter + +--- + +## 🧪 Тестирование + +### Ручное тестирование +```bash +# Простой тест +curl -X POST http://localhost:3001/v1/chat/completions \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer your-api-key" \ + -d '{"messages":[{"role":"user","content":"Test"}]}' + +# Тест streaming +curl -X POST http://localhost:3001/v1/chat/completions \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer your-api-key" \ + -d '{"messages":[{"role":"user","content":"Test"}],"stream":true}' +``` + +### Автоматическое тестирование +В проекте есть готовые тесты: +```bash +npm run test:completion +npm run test:openai +``` + +--- + +## 📈 Лимиты и ограничения + +### Текущие лимиты +- **Максимальный размер запроса**: 10MB +- **Timeout**: 60 секунд +- **Rate limiting**: настраивается администратором +- **Минимальный баланс**: 1 рубль + +### Рекомендации +- Используйте подходящую модель для вашей задачи +- Оптимизируйте длину промптов +- Мониторьте расход баланса +- Обрабатывайте ошибки корректно + +--- + +## 🔗 Совместимость с OpenAI SDK + +API полностью совместим с OpenAI SDK. Достаточно изменить base URL: + +### Python (openai) +```python +import openai + +client = openai.OpenAI( + api_key="sk-user-your-api-key", + base_url="http://localhost:3001/v1" +) + +response = client.chat.completions.create( + model="google/gemini-2.5-flash-lite", + messages=[ + {"role": "user", "content": "Привет!"} + ] +) +``` + +### JavaScript (openai) +```javascript +import OpenAI from 'openai'; + +const openai = new OpenAI({ + apiKey: 'sk-user-your-api-key', + baseURL: 'http://localhost:3001/v1', +}); + +const completion = await openai.chat.completions.create({ + model: 'google/gemini-2.5-flash-lite', + messages: [ + {role: 'user', content: 'Привет!'}, + ], +}); +``` + +--- + +## 🆘 Поддержка и отладка + +### Частые проблемы +1. **401 Unauthorized** - проверьте API ключ +2. **402 Payment Required** - пополните баланс +3. **400 Bad Request** - проверьте формат запроса +4. **500 Internal Error** - обратитесь в поддержку + +### Отладка +- Проверьте логи в `logs/combined-YYYY-MM-DD.log` +- Используйте Request ID из заголовка `X-Request-ID` +- Мониторьте баланс через `/vk-test` + +### Контакты +- **Документация**: http://localhost:8080 +- **Поддержка**: support@gptutor.site +- **GitHub**: https://github.com/your-repo/gptutor-backend-v2 + + diff --git a/GPTutor-Backend-v2/docs/MODELS_API.md b/GPTutor-Backend-v2/docs/MODELS_API.md new file mode 100644 index 00000000..bb9600e7 --- /dev/null +++ b/GPTutor-Backend-v2/docs/MODELS_API.md @@ -0,0 +1,99 @@ +# Models API Documentation + +API для получения информации о моделях LLM с ценами в рублях. + +## Endpoints + +### GET /v1/models + +Получить модели только от популярных провайдеров с ценами в рублях. **Публичный endpoint - авторизация не требуется.** + +**Поддерживаемые провайдеры:** x-ai, deepseek, google, qwen, perplexity, mistralai, openai + +**Фильтрация:** Исключены бесплатные модели (содержащие ":free" в названии) + +**Сортировка:** Модели отсортированы по цене (самые дорогие сверху), затем по дате создания (самые новые сверху) + +**Ответ:** +```json +{ + "success": true, + "data": { + "models": [ + { + "id": "google/gemini-2.5-flash-lite-preview-09-2025", + "name": "Google: Gemini 2.5 Flash Lite Preview 09-2025", + "description": "Gemini 2.5 Flash-Lite is a lightweight reasoning model...", + "context_length": 1048576, + "architecture": { + "modality": "text+image->text", + "input_modalities": ["file", "image", "text", "audio"], + "output_modalities": ["text"], + "tokenizer": "Gemini", + "instruct_type": null + }, + "pricing_rub": { + "prompt": 0.000009, + "completion": 0.000036, + "request": 0, + "image": 0, + "web_search": 0, + "internal_reasoning": 0 + }, + "top_provider": { + "context_length": 1048576, + "max_completion_tokens": 65536, + "is_moderated": false + }, + "supported_parameters": [ + "include_reasoning", + "max_tokens", + "reasoning", + "response_format", + "seed", + "stop", + "structured_outputs", + "temperature", + "tool_choice", + "tools", + "top_p" + ] + } + ], + "total": 45, + "providers": ["x-ai", "deepseek", "google", "qwen", "perplexity", "mistralai", "openai"], + "currency": "RUB", + "exchangeRate": 90, + "lastUpdated": "2025-01-28T10:30:00.000Z" + } +} +``` + +## Коды ошибок + +- `400 Bad Request` - неверные параметры запроса +- `500 Internal Server Error` - внутренняя ошибка сервера + +## Примеры использования + +### Получение моделей популярных провайдеров +```bash +curl -X GET "http://localhost:3001/v1/models" +``` + +## Структура ценообразования + +Все цены возвращаются в рублях и рассчитываются по формуле: +``` +цена_в_рублях = цена_в_долларах * курс_USD_to_RUB +``` + +Текущий курс: 90 рублей за доллар (можно изменить через `setUsdToRubRate()`). + +### Типы цен: +- `prompt` - цена за входной токен +- `completion` - цена за выходной токен +- `request` - фиксированная цена за запрос +- `image` - цена за изображение +- `web_search` - цена за веб-поиск +- `internal_reasoning` - цена за внутренние рассуждения diff --git a/GPTutor-Backend-v2/docs/QUICK_START.md b/GPTutor-Backend-v2/docs/QUICK_START.md new file mode 100644 index 00000000..66073aa6 --- /dev/null +++ b/GPTutor-Backend-v2/docs/QUICK_START.md @@ -0,0 +1,160 @@ +# 🚀 Быстрый старт - GPTutor API Documentation + +## Запуск документации + +### Одной командой +```bash +npm run docs +``` + +Документация будет доступна по адресу: **http://localhost:8080** + +### Автоматическое открытие в браузере (Windows) +```bash +npm run docs:open +``` + +## 📋 Доступные страницы + +После запуска сервера будут доступны: + +| URL | Описание | +|-----|----------| +| http://localhost:8080/ | 🏠 Главная страница с навигацией | +| http://localhost:8080/index.html | 📖 API документация (светлая тема) | +| http://localhost:8080/dark.html | 🌙 API документация (темная тема) | +| http://localhost:8080/test-examples.html | 🧪 Интерактивное тестирование | +| http://localhost:8080/openapi.yaml | 📄 OpenAPI спецификация | +| http://localhost:8080/CHAT_COMPLETIONS_API.md | 📚 Подробная документация | + +## ✨ Возможности + +### 🎨 Scalar UI +- Современный и красивый интерфейс +- Намного лучше стандартного Swagger UI +- Поддержка светлой и темной темы + +### 🔧 Try-it функционал +- Тестирование API прямо в браузере +- Автоматическая генерация примеров кода +- Поддержка всех параметров запроса + +### 📖 Богатый контент +- Подробные описания в Markdown +- Примеры для всех endpoints +- Коды ошибок и их объяснения +- Информация о стоимости и биллинге + +### 🧪 Интерактивное тестирование +- Отдельная страница для тестирования +- Готовые примеры запросов +- Поддержка streaming режима +- Отображение стоимости запросов + +## 🔧 Настройка + +### Изменение порта +Отредактируйте `docs/serve.js`: +```javascript +const port = 8080; // измените на нужный порт +``` + +### Кастомизация тем +Отредактируйте `docs/index.html` или `docs/dark.html`: +```javascript +data-configuration='{ + "theme": "purple", // purple, saturn, mars + "darkMode": false, // true/false + "layout": "modern" // modern, classic +}' +``` + +## 📤 Деплой + +### Статические файлы +Скопируйте файлы из папки `docs/` на любой статический хостинг: +- GitHub Pages +- Vercel +- Netlify +- AWS S3 + +### Docker +```dockerfile +FROM nginx:alpine +COPY docs/ /usr/share/nginx/html/ +EXPOSE 80 +``` + +### Nginx +```nginx +server { + listen 80; + root /path/to/docs; + index welcome.html; + + location / { + try_files $uri $uri/ =404; + } +} +``` + +## 🛠 Разработка + +### Структура файлов +``` +docs/ +├── welcome.html # Главная страница +├── index.html # Scalar (светлая тема) +├── dark.html # Scalar (темная тема) +├── test-examples.html # Интерактивное тестирование +├── openapi.yaml # OpenAPI спецификация +├── serve.js # Сервер разработки +├── CHAT_COMPLETIONS_API.md # Подробная документация +└── README.md # Полная документация +``` + +### Редактирование OpenAPI +Основной файл спецификации: `docs/openapi.yaml` + +После изменений перезапустите сервер: +```bash +# Остановите сервер (Ctrl+C) +npm run docs +``` + +### Добавление новых страниц +1. Создайте HTML файл в папке `docs/` +2. Добавьте ссылку в `welcome.html` +3. Обновите сервер если нужно + +## 🎯 Примеры использования + +### Тестирование API +1. Запустите документацию: `npm run docs` +2. Откройте http://localhost:8080/test-examples.html +3. Введите ваш API ключ +4. Выберите пример или введите свой запрос +5. Нажмите "Отправить запрос" + +### Изучение API +1. Откройте http://localhost:8080/index.html +2. Изучите доступные endpoints +3. Используйте Try-it для тестирования +4. Копируйте примеры кода + +### Интеграция с клиентами +1. Скачайте OpenAPI спецификацию: http://localhost:8080/openapi.yaml +2. Используйте генераторы кода (OpenAPI Generator) +3. Или используйте готовые SDK с измененным base URL + +## 🔗 Полезные ссылки + +- [Scalar Documentation](https://github.com/scalar/scalar) +- [OpenAPI 3.0.3 Specification](https://spec.openapis.org/oas/v3.0.3) +- [GPTutor Backend Repository](https://github.com/your-repo/gptutor-backend-v2) + +--- + +**Готово!** Теперь у вас есть красивая и функциональная документация API 🎉 + + diff --git a/GPTutor-Backend-v2/docs/RATE_LIMITING.md b/GPTutor-Backend-v2/docs/RATE_LIMITING.md new file mode 100644 index 00000000..350062a0 --- /dev/null +++ b/GPTutor-Backend-v2/docs/RATE_LIMITING.md @@ -0,0 +1,180 @@ +# Rate Limiting Documentation + +## Обзор + +В проекте GPTutor Backend v2 реализована система rate limiting для защиты от злоупотреблений и обеспечения стабильной работы API. + +## Архитектура + +### Компоненты + +1. **rateLimitMiddleware.ts** - основной middleware для rate limiting +2. **rateLimitConfig.ts** - конфигурация лимитов для разных роутов и окружений +3. **Интеграция в контроллеры** - каждый контроллер использует специфичные лимиты + +### Принцип работы + +- Каждый роут имеет свои лимиты запросов в минуту +- Лимиты различаются в зависимости от окружения (development, staging, production) +- Ключи для rate limiting генерируются на основе IP адреса и ID пользователя +- Автоматическая очистка устаревших записей каждые 5 минут + +## Конфигурация + +### Текущие лимиты + +| Роут | Development | Staging | Production | +|------|-------------|---------|------------| +| `/health` | 100/мин | 100/мин | 100/мин | +| `/vk-test` | 30/мин | 30/мин | 30/мин | +| `/update-token` | 5/мин | 5/мин | 5/мин | +| `/upload` | 50/мин | 8/мин | 5/мин | +| `/v1/chat/completions` | 100/мин | 15/мин | 10/мин | +| `/v1/models` | 50/мин | 50/мин | 50/мин | + +### Настройка лимитов + +Для изменения лимитов отредактируйте файл `src/config/rateLimitConfig.ts`: + +```typescript +export const RATE_LIMIT_CONFIG_BY_ENV = { + production: { + '/v1/chat/completions': { + max: 10, // количество запросов + timeWindow: 60 * 1000, // окно времени в миллисекундах + }, + }, +}; +``` + +## Использование + +### В контроллерах + +```typescript +import { createRateLimitMiddleware, getRateLimitConfig } from '../middleware/rateLimitMiddleware'; + +// Создание middleware для конкретного роута +const rateLimit = createRateLimitMiddleware(getRateLimitConfig('/your-route')!); + +// Применение в роуте +this.fastify.post( + '/your-route', + { preHandler: rateLimit }, + this.yourHandler.bind(this) +); +``` + +### Кастомные лимиты + +```typescript +const customRateLimit = createRateLimitMiddleware({ + max: 5, + timeWindow: 60 * 1000, + keyGenerator: (request) => `custom:${request.ip}`, + onLimitReached: (request, reply) => { + reply.code(429).send({ error: 'Custom rate limit exceeded' }); + } +}); +``` + +## Мониторинг + +### Логирование + +При превышении лимитов записываются логи с информацией: +- IP адрес клиента +- URL запроса +- Метод HTTP +- Количество запросов +- Максимальный лимит +- Время окна + +### HTTP заголовки + +При каждом запросе возвращаются заголовки: +- `X-RateLimit-Limit` - максимальный лимит +- `X-RateLimit-Remaining` - оставшиеся запросы +- `X-RateLimit-Reset` - время сброса лимита (Unix timestamp) + +## Обработка ошибок + +### Стандартная ошибка + +```json +{ + "error": "Too Many Requests", + "message": "Rate limit exceeded. Maximum 10 requests per 60 seconds.", + "retryAfter": 45 +} +``` + +### Кастомная обработка + +```typescript +const rateLimit = createRateLimitMiddleware({ + max: 5, + timeWindow: 60 * 1000, + onLimitReached: (request, reply) => { + // Кастомная логика обработки превышения лимита + logger.warn('Custom rate limit exceeded', { ip: request.ip }); + reply.code(429).send({ + error: 'Custom limit exceeded', + retryAfter: 60 + }); + } +}); +``` + +## Производительность + +### Оптимизации + +1. **In-memory store** - быстрый доступ к данным о лимитах +2. **Периодическая очистка** - автоматическое удаление устаревших записей +3. **Эффективные ключи** - оптимизированная генерация ключей для rate limiting + +### Мониторинг производительности + +```typescript +// Логирование производительности rate limiting +logger.info('Rate limit check', { + duration: Date.now() - startTime, + key, + count: record.count +}); +``` + +## Безопасность + +### Защита от злоупотреблений + +1. **Разные лимиты для разных роутов** - критичные операции имеют более строгие лимиты +2. **Комбинированные ключи** - учет IP и пользователя для более точного контроля +3. **Окружение-специфичные лимиты** - более строгие лимиты в продакшене + +### Рекомендации + +1. **Мониторинг** - отслеживайте логи превышения лимитов +2. **Настройка** - адаптируйте лимиты под нагрузку +3. **Тестирование** - проверяйте лимиты в разных окружениях + +## Troubleshooting + +### Частые проблемы + +1. **Слишком строгие лимиты** - увеличьте `max` в конфигурации +2. **Слишком мягкие лимиты** - уменьшите `max` для критичных роутов +3. **Проблемы с производительностью** - проверьте размер store и частоту очистки + +### Отладка + +```typescript +// Включение debug логов +logger.debug('Rate limit check', { + key, + count: record.count, + max: config.max, + timeWindow: config.timeWindow +}); +``` diff --git a/GPTutor-Backend-v2/docs/README-internal.md b/GPTutor-Backend-v2/docs/README-internal.md new file mode 100644 index 00000000..2d287475 --- /dev/null +++ b/GPTutor-Backend-v2/docs/README-internal.md @@ -0,0 +1,163 @@ +# 🔧 GPTutor Internal API Documentation + +Внутренняя документация API для административных операций GPTutor. + +## 📋 Обзор + +Этот набор документации предназначен **только для внутреннего использования** администраторами системы GPTutor. Содержит все административные endpoints, которые не должны быть видны в публичной документации. + +## 🚀 Быстрый старт + +### Установка зависимостей + +```bash +cd docs +npm install +``` + +### Запуск сервера документации + +```bash +npm start +``` + +Документация будет доступна по адресу: http://localhost:3002 + +### Разработка + +```bash +npm run dev +``` + +## 📁 Структура файлов + +``` +docs/ +├── internal-api.yaml # OpenAPI спецификация для внутренних роутов +├── internal.html # HTML страница с документацией +├── serve-internal.js # Сервер для обслуживания документации +├── package.json # Зависимости для сервера документации +└── README-internal.md # Этот файл +``` + +## 🔐 Доступные Endpoints + +### System +- `GET /health` - Проверка состояния сервера + +### Authentication +- `GET /vk-test` - Тест VK авторизации +- `POST /update-token` - Обновление API токена пользователя + +### Models +- `GET /v1/models` - Получение списка доступных моделей + +### Chat Completions +- `POST /v1/chat/completions` - Создание chat completion + +## 🔑 Авторизация + +### VK Auth +Для административных операций требуется VK подпись: +``` +Authorization: Bearer +``` + +### API Key Auth +Для пользовательских операций требуется API ключ: +``` +Authorization: Bearer sk-... +``` + +## 🛠️ Разработка + +### Добавление нового endpoint + +1. Добавьте endpoint в соответствующий контроллер +2. Обновите `internal-api.yaml` с описанием нового endpoint +3. Перезапустите сервер документации + +### Обновление документации + +1. Отредактируйте `internal-api.yaml` +2. При необходимости обновите `internal.html` +3. Перезапустите сервер + +## 🔒 Безопасность + +⚠️ **ВАЖНО:** Эта документация содержит внутренние endpoints и не должна быть доступна публично! + +- Используйте только в защищенной сети +- Ограничьте доступ по IP адресам +- Не размещайте на публичных серверах без аутентификации + +## 📊 Мониторинг + +Сервер документации предоставляет health check endpoint: +``` +GET /health +``` + +## 🐛 Отладка + +### Проверка OpenAPI спецификации + +```bash +curl http://localhost:3002/internal-api.yaml +``` + +### Проверка health check + +```bash +curl http://localhost:3002/health +``` + +## 📝 Примеры использования + +### Проверка состояния сервера + +```bash +curl http://localhost:3001/health +``` + +### Тест VK авторизации + +```bash +curl -H "Authorization: Bearer " \ + http://localhost:3001/vk-test +``` + +### Обновление токена пользователя + +```bash +curl -X POST \ + -H "Authorization: Bearer " \ + http://localhost:3001/update-token +``` + +### Получение списка моделей + +```bash +curl http://localhost:3001/v1/models +``` + +## 🔄 Обновления + +При обновлении API: + +1. Обновите `internal-api.yaml` +2. Проверьте совместимость с существующими клиентами +3. Обновите версию в `package.json` +4. Перезапустите сервер документации + +## 📞 Поддержка + +Для вопросов по внутренней документации обращайтесь к команде разработки GPTutor. + +--- + +**Версия:** 2.0.0 +**Последнее обновление:** 2024-01-15 +**Автор:** GPTutor Team + + diff --git a/GPTutor-Backend-v2/docs/README.md b/GPTutor-Backend-v2/docs/README.md new file mode 100644 index 00000000..f816b9d7 --- /dev/null +++ b/GPTutor-Backend-v2/docs/README.md @@ -0,0 +1,152 @@ +# GPTutor Backend v2 API Documentation + +Красивая интерактивная документация API, созданная с помощью **Scalar**. + +## 🚀 Быстрый старт + +### Запуск документации + +```bash +# Запустить сервер документации +npm run docs + +# Или запустить и сразу открыть в браузере (Windows) +npm run docs:open +``` + +Документация будет доступна по адресу: **http://localhost:8080** + +### Доступные страницы + +- **Light Theme**: http://localhost:8080/ (по умолчанию) +- **Dark Theme**: http://localhost:8080/dark.html +- **OpenAPI Spec**: http://localhost:8080/openapi.yaml + +## ✨ Возможности + +### 🎨 Современный дизайн +- Красивый и чистый интерфейс Scalar +- Поддержка светлой и темной темы +- Адаптивный дизайн для мобильных устройств + +### 📖 Богатое содержание +- Подробные описания всех endpoints +- Примеры запросов и ответов +- Интерактивное тестирование API +- Markdown поддержка в описаниях + +### 🔧 Интерактивность +- Try-it функционал для всех endpoints +- Автоматическая генерация кода на разных языках +- Поиск по документации (Ctrl+K) +- Копирование примеров кода + +## 📚 Структура документации + +### Health Check (`/health`) +- Проверка состояния сервера +- Используется для мониторинга + +### VK Authentication (`/vk-test`) +- Тестирование VK авторизации +- Получение информации о пользователе +- Проверка баланса + +### Chat Completions (`/v1/chat/completions`) +- OpenAI-совместимый API +- Поддержка streaming режима +- Множество моделей через OpenRouter +- Автоматический расчет стоимости + +## 🔐 Аутентификация + +### VK Токены +``` +Authorization: Bearer vk1.a.abc123... +``` + +### API Ключи +``` +Authorization: Bearer sk-user-abc123def456... +``` + +## 💰 Стоимость и биллинг + +- Стоимость рассчитывается автоматически +- Курс доллара: **90 рублей** +- Подробная информация в каждом ответе +- Автоматическое списание с баланса + +## 🛠 Технические детали + +### OpenAPI 3.0.3 +Документация основана на стандарте OpenAPI 3.0.3 с расширениями для GPTutor. + +### Scalar +Использует последнюю версию Scalar для современного и красивого UI. + +### Кастомизация +Можно настроить темы, цвета и поведение через конфигурацию в HTML файлах. + +## 📝 Редактирование + +### OpenAPI спецификация +Основной файл: `docs/openapi.yaml` + +### HTML страницы +- `docs/index.html` - светлая тема +- `docs/dark.html` - темная тема + +### Сервер документации +`docs/serve.js` - простой статический сервер для разработки + +## 🚢 Деплой + +### Статические файлы +Можно разместить файлы `index.html`, `dark.html` и `openapi.yaml` на любом статическом хостинге: +- GitHub Pages +- Vercel +- Netlify +- AWS S3 + +### Nginx конфигурация +```nginx +location /docs { + alias /path/to/docs; + index index.html; + try_files $uri $uri/ =404; + + # CORS headers + add_header Access-Control-Allow-Origin *; +} +``` + +## 🎯 Примеры использования + +### Тестирование API +1. Откройте документацию +2. Перейдите к нужному endpoint +3. Нажмите "Try it" +4. Заполните параметры +5. Нажмите "Send" + +### Генерация кода +1. Выберите endpoint +2. Настройте параметры +3. Выберите язык программирования +4. Скопируйте готовый код + +### Поиск +- Нажмите `Ctrl+K` или `Cmd+K` +- Введите поисковый запрос +- Быстро найдите нужный endpoint или информацию + +--- + +## 🔗 Полезные ссылки + +- [Scalar Documentation](https://github.com/scalar/scalar) +- [OpenAPI 3.0.3 Specification](https://spec.openapis.org/oas/v3.0.3) +- [GPTutor Backend Repository](https://github.com/your-repo/gptutor-backend-v2) + + diff --git a/GPTutor-Backend-v2/docs/USER_GUIDE.md b/GPTutor-Backend-v2/docs/USER_GUIDE.md new file mode 100644 index 00000000..d6f1c966 --- /dev/null +++ b/GPTutor-Backend-v2/docs/USER_GUIDE.md @@ -0,0 +1,97 @@ +# 🤖 GPTutor AI API - Руководство пользователя + +## 🎯 Что это такое? + +GPTutor AI API - это ваш персональный доступ к мощным искусственным интеллектам. Вы можете задавать любые вопросы и получать умные ответы на русском языке. + +## 🚀 Как начать? + +### 1. Получите API ключ +Обратитесь к администратору системы для получения вашего персонального API ключа. + +### 2. Откройте документацию +Перейдите по адресу: **http://localhost:8080** + +### 3. Попробуйте API +В разделе "Try it" вы можете протестировать API прямо в браузере! + +## 💬 Как задавать вопросы? + +### Простые вопросы +``` +"Как приготовить борщ?" +"Объясни квантовую физику простыми словами" +"Напиши стихотворение о весне" +``` + +### Сложные задачи +``` +"Создай веб-сайт на React" +"Напиши эссе о влиянии технологий на общество" +"Помоги с домашним заданием по математике" +``` + +## 🤖 Какие AI доступны? + +### 🟢 Быстрые модели (рекомендуется) +- **Gemini 2.0 Flash** - очень быстрая, отлично для простых вопросов +- **Claude Haiku** - быстрая и качественная + +### 🔵 Мощные модели +- **GPT-4** - самая умная модель для сложных задач +- **Claude Sonnet** - отлично для творчества и анализа + +## 💰 Стоимость + +- **Короткие вопросы** (до 100 слов): ~1-3 рубля +- **Средние вопросы** (100-500 слов): ~3-10 рублей +- **Длинные ответы** (500+ слов): ~10-30 рублей + +### Как сэкономить? +- Задавайте конкретные вопросы +- Используйте быстрые модели для простых задач +- Избегайте очень длинных запросов + +## ⚡ Режимы работы + +### Обычный режим (рекомендуется) +- Получаете полный ответ сразу +- Подходит для большинства вопросов +- Быстрее и дешевле + +### Потоковый режим (Streaming) +- Видите ответ по мере его появления +- Создает ощущение "живого" общения +- Подходит для длинных текстов + +## 🔒 Безопасность + +- Ваши вопросы не сохраняются +- API ключ защищен шифрованием +- Данные не передаются третьим лицам + +## 🆘 Что делать, если что-то не работает? + +1. **Проверьте баланс** - возможно, недостаточно средств +2. **Проверьте API ключ** - убедитесь, что он правильный +3. **Попробуйте другую модель** - возможно, выбранная модель перегружена +4. **Обратитесь в поддержку** - мы всегда поможем! + +## 📞 Поддержка + +- 📧 Email: support@gptutor.site +- 💬 Telegram: @gptutor_support +- 📖 Документация: http://localhost:8080 + +## 🎁 Бонусы + +- **Первый запрос бесплатно** - попробуйте без риска +- **Скидки при пополнении** - чем больше, тем выгоднее +- **Приоритетная поддержка** - быстрые ответы на вопросы +- **Новые модели первыми** - доступ к самым свежим AI + +--- + +**Готовы начать?** Откройте http://localhost:8080 и попробуйте задать свой первый вопрос! 🚀 + + diff --git a/GPTutor-Backend-v2/docs/dark.html b/GPTutor-Backend-v2/docs/dark.html new file mode 100644 index 00000000..623136df --- /dev/null +++ b/GPTutor-Backend-v2/docs/dark.html @@ -0,0 +1,143 @@ + + + + GPTutor Backend v2 API Documentation (Dark Theme) + + + + + + + + + + + + diff --git a/GPTutor-Backend-v2/docs/index.html b/GPTutor-Backend-v2/docs/index.html new file mode 100644 index 00000000..6a01c9dc --- /dev/null +++ b/GPTutor-Backend-v2/docs/index.html @@ -0,0 +1,184 @@ + + + + GPTutor Backend v2 API Documentation + + + + + + + + + + + + diff --git a/GPTutor-Backend-v2/docs/internal-api.yaml b/GPTutor-Backend-v2/docs/internal-api.yaml new file mode 100644 index 00000000..f566f5a4 --- /dev/null +++ b/GPTutor-Backend-v2/docs/internal-api.yaml @@ -0,0 +1,985 @@ +openapi: 3.0.3 +info: + title: GPTutor Internal API + version: 2.0.0 + description: | + # GPTutor Internal API + + Внутренние административные endpoints для управления системой GPTutor. + + **⚠️ ВНИМАНИЕ:** Этот API предназначен только для внутреннего использования администраторами системы. + + ## Доступные роуты + + ### Health Check + - `GET /health` - Проверка состояния сервера + + ### Аутентификация + - `GET /vk-test` - Тест VK авторизации + - `POST /update-token` - Обновление API токена пользователя + + ### Модели + - `GET /v1/models` - Получение списка доступных моделей + + ### Chat Completions + - `POST /v1/chat/completions` - Создание chat completion + + ### Files + - `POST /upload` - Загрузка файла в S3 + - `GET /files` - Получение списка файлов пользователя + - `DELETE /files/:fileId` - Удаление файла + + ## Безопасность + + Все endpoints требуют соответствующей авторизации: + - **VK Auth** - для административных операций + - **API Key** - для пользовательских операций + +servers: + - url: http://localhost:3001 + description: Development server + - url: https://api.gptutor.site + description: Production server + +paths: + /health: + get: + tags: [System] + summary: Health Check + description: | + Проверяет состояние сервера и возвращает базовую информацию о системе. + + **Использование:** + - Мониторинг состояния сервера + - Проверка доступности API + - Load balancer health checks + responses: + '200': + description: Сервер работает нормально + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: true + data: + type: object + properties: + status: + type: string + example: "ok" + description: "Статус сервера" + timestamp: + type: string + format: date-time + example: "2024-01-15T10:30:00Z" + description: "Время проверки" + examples: + healthy: + summary: Сервер работает + value: + success: true + data: + status: "ok" + timestamp: "2024-01-15T10:30:00Z" + '500': + description: Внутренняя ошибка сервера + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /vk-test: + get: + tags: [Authentication] + summary: Тест VK авторизации + description: | + Тестирует VK авторизацию и возвращает информацию о пользователе. + + **Использование:** + - Отладка VK авторизации + - Проверка корректности VK подписи + - Получение информации о пользователе + + **Требует:** VK подпись в заголовке Authorization + security: + - VkAuth: [] + responses: + '200': + description: Успешная авторизация + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: true + data: + type: object + properties: + message: + type: string + example: "VK authorization successful!" + vkData: + type: object + description: "Данные от VK" + properties: + vk_user_id: + type: string + vk_app_id: + type: string + vk_is_app_user: + type: string + vk_language: + type: string + vk_platform: + type: string + vk_ts: + type: string + dbUser: + type: object + properties: + id: + type: string + description: "ID пользователя в БД" + vkId: + type: string + description: "VK ID пользователя" + balance: + type: number + description: "Баланс пользователя" + apiKey: + type: string + description: "API ключ пользователя" + isActive: + type: boolean + description: "Активен ли пользователь" + createdAt: + type: string + format: date-time + description: "Дата создания" + updatedAt: + type: string + format: date-time + description: "Дата обновления" + timestamp: + type: string + format: date-time + examples: + success: + summary: Успешная VK авторизация + value: + success: true + data: + message: "VK authorization successful!" + vkData: + vk_user_id: "123456789" + vk_app_id: "51602327" + vk_is_app_user: "1" + vk_language: "ru" + vk_platform: "web" + vk_ts: "1642234567" + dbUser: + id: "user_abc123" + vkId: "123456789" + balance: 10.5 + apiKey: "sk-abc123..." + isActive: true + createdAt: "2024-01-01T00:00:00Z" + updatedAt: "2024-01-15T10:30:00Z" + timestamp: "2024-01-15T10:30:00Z" + '401': + $ref: '#/components/responses/Unauthorized' + '500': + $ref: '#/components/responses/InternalError' + + /update-token: + post: + tags: [Authentication] + summary: Обновление API токена + description: | + Генерирует новый API ключ для пользователя. Старый ключ становится недействительным. + + **Использование:** + - Обновление скомпрометированного API ключа + - Ротация ключей безопасности + - Административное управление пользователями + + **Требует:** VK авторизацию + security: + - VkAuth: [] + responses: + '200': + description: Токен успешно обновлен + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: true + data: + type: object + properties: + message: + type: string + example: "API token updated successfully!" + newApiKey: + type: string + description: "Новый API ключ" + example: "sk-abc123def456ghi789jkl012mno345pqr678stu901vwx234yz567890" + user: + type: object + properties: + id: + type: string + description: "ID пользователя" + vkId: + type: string + description: "VK ID пользователя" + balance: + type: number + description: "Баланс пользователя" + isActive: + type: boolean + description: "Активен ли пользователь" + updatedAt: + type: string + format: date-time + description: "Время обновления" + timestamp: + type: string + format: date-time + examples: + success: + summary: Успешное обновление токена + value: + success: true + data: + message: "API token updated successfully!" + newApiKey: "sk-abc123def456ghi789jkl012mno345pqr678stu901vwx234yz567890" + user: + id: "user_123" + vkId: "vk_456" + balance: 10.5 + isActive: true + updatedAt: "2024-01-15T10:30:00Z" + timestamp: "2024-01-15T10:30:00Z" + '401': + $ref: '#/components/responses/Unauthorized' + '500': + $ref: '#/components/responses/InternalError' + + /v1/models: + get: + tags: [Models] + summary: Получение списка моделей + description: | + Возвращает список всех доступных AI моделей с информацией о ценах и провайдерах. + + **Использование:** + - Получение актуального списка моделей + - Проверка доступности моделей + - Анализ цен на модели + + **Особенности:** + - Модели сортируются по цене (самые дорогие сверху) + - Включает информацию о провайдерах + - Показывает время последнего обновления + responses: + '200': + description: Список моделей успешно получен + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: true + data: + type: object + properties: + models: + type: array + items: + $ref: '#/components/schemas/Model' + description: "Список доступных моделей" + total: + type: integer + description: "Общее количество моделей" + example: 150 + providers: + type: array + items: + type: string + description: "Список провайдеров" + example: ["x-ai", "deepseek", "google", "qwen", "perplexity", "mistralai", "openai"] + lastUpdated: + type: string + format: date-time + description: "Время последнего обновления" + examples: + success: + summary: Успешное получение моделей + value: + success: true + data: + models: + - id: "openai/gpt-4o" + name: "GPT-4o" + description: "Most capable GPT-4 model" + pricing_rub: + prompt: 0.15 + completion: 0.6 + context_length: 128000 + created: 1642234567 + total: 150 + providers: ["openai", "anthropic", "google", "deepseek"] + lastUpdated: "2024-01-15T10:30:00Z" + '503': + description: Сервис моделей недоступен + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + service_unavailable: + summary: Сервис недоступен + value: + error: "Models service not ready" + '500': + $ref: '#/components/responses/InternalError' + + /v1/chat/completions: + post: + tags: [Chat Completions] + summary: Создание chat completion + description: | + Создает completion для чата с поддержкой streaming и автоматическим выбором модели. + + **Использование:** + - Генерация ответов от AI + - Streaming режим для реального времени + - Автоматический fallback между моделями + + **Особенности:** + - Поддержка streaming режима + - Автоматический расчет стоимости + - Fallback на другие модели при ошибках + - Поддержка всех параметров OpenAI API + security: + - ApiKeyAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ChatCompletionRequest' + examples: + simple: + summary: Простой запрос + value: + model: "google/gemini-2.5-flash-lite" + messages: + - role: "user" + content: "Привет! Как дела?" + streaming: + summary: Streaming запрос + value: + model: "google/gemini-2.5-flash-lite" + messages: + - role: "user" + content: "Расскажи историю" + stream: true + max_tokens: 150 + advanced: + summary: Продвинутый запрос + value: + model: "anthropic/claude-3-haiku" + messages: + - role: "user" + content: "Объясни квантовую физику простыми словами" + max_tokens: 500 + temperature: 0.7 + responses: + '200': + description: Успешный ответ + content: + application/json: + schema: + $ref: '#/components/schemas/ChatCompletionResponse' + text/event-stream: + schema: + type: string + description: | + Streaming ответ в формате Server-Sent Events: + ``` + data: {"choices":[{"delta":{"content":"Hello"}}]} + data: {"choices":[{"delta":{"content":" there!"}}]} + data: [DONE] + ``` + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '402': + description: Недостаточно средств + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + insufficient_balance: + summary: Недостаточно средств + value: + error: "Insufficient balance" + '500': + $ref: '#/components/responses/InternalError' + + /upload: + post: + tags: [Files] + summary: Загрузка файла в S3 + description: | + Загружает файл в Yandex Object Storage с автоматической оптимизацией. + + **Использование:** + - Загрузка изображений с оптимизацией + - Загрузка документов с сжатием + - Загрузка текстовых файлов + + **Особенности:** + - Автоматическая оптимизация изображений (качество 60%) + - Сжатие PDF файлов + - Поддержка файлов до 50MB + - Генерация уникальных имен файлов + + **Поддерживаемые типы:** + - **Изображения:** jpg, jpeg, png, gif, bmp, svg, webp, tiff + - **Документы:** pdf, doc, docx, xls, xlsx, csv + - **Текстовые:** txt, js, html, css, json, xml, md, log, py, java, c, cpp, sql + security: + - VkAuth: [] + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + file: + type: string + format: binary + description: "Файл для загрузки" + examples: + image: + summary: Загрузка изображения + value: + file: "image.jpg" + document: + summary: Загрузка документа + value: + file: "document.pdf" + responses: + '200': + description: Файл успешно загружен + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: true + data: + type: object + properties: + message: + type: string + example: "File uploaded successfully!" + file: + type: object + properties: + id: + type: string + description: "ID файла в БД" + name: + type: string + description: "Оригинальное имя файла" + type: + type: string + description: "MIME тип файла" + url: + type: string + description: "URL файла в S3" + size: + type: integer + description: "Размер файла в байтах" + createdAt: + type: string + format: date-time + description: "Время загрузки" + timestamp: + type: string + format: date-time + examples: + success: + summary: Успешная загрузка + value: + success: true + data: + message: "File uploaded successfully!" + file: + id: "file_abc123" + name: "document.pdf" + type: "application/pdf" + url: "https://gptutor-bucket.storage.yandexcloud.net/uuid.pdf" + size: 1024000 + createdAt: "2024-01-15T10:30:00Z" + timestamp: "2024-01-15T10:30:00Z" + '400': + description: Неверный запрос + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + no_file: + summary: Файл не предоставлен + value: + error: "No file provided" + unsupported_type: + summary: Неподдерживаемый тип файла + value: + error: "Unsupported file type" + '401': + $ref: '#/components/responses/Unauthorized' + '413': + description: Файл слишком большой + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + file_too_large: + summary: Файл превышает лимит + value: + error: "File too large. Maximum size is 50MB" + '500': + $ref: '#/components/responses/InternalError' + + /files: + get: + tags: [Files] + summary: Получение списка файлов пользователя + description: | + Возвращает список всех файлов, загруженных пользователем. + + **Использование:** + - Просмотр загруженных файлов + - Получение метаданных файлов + - Управление файлами пользователя + security: + - VkAuth: [] + responses: + '200': + description: Список файлов успешно получен + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: true + data: + type: object + properties: + message: + type: string + example: "Files retrieved successfully!" + files: + type: array + items: + type: object + properties: + id: + type: string + description: "ID файла" + name: + type: string + description: "Имя файла" + type: + type: string + description: "MIME тип" + url: + type: string + description: "URL файла" + size: + type: integer + description: "Размер в байтах" + createdAt: + type: string + format: date-time + description: "Время загрузки" + total: + type: integer + description: "Общее количество файлов" + timestamp: + type: string + format: date-time + examples: + success: + summary: Список файлов + value: + success: true + data: + message: "Files retrieved successfully!" + files: + - id: "file_abc123" + name: "document.pdf" + type: "application/pdf" + url: "https://gptutor-bucket.storage.yandexcloud.net/uuid.pdf" + size: 1024000 + createdAt: "2024-01-15T10:30:00Z" + - id: "file_def456" + name: "image.jpg" + type: "image/jpeg" + url: "https://gptutor-bucket.storage.yandexcloud.net/uuid2.jpg" + size: 512000 + createdAt: "2024-01-15T11:00:00Z" + total: 2 + timestamp: "2024-01-15T11:30:00Z" + '401': + $ref: '#/components/responses/Unauthorized' + '500': + $ref: '#/components/responses/InternalError' + + /files/{fileId}: + delete: + tags: [Files] + summary: Удаление файла + description: | + Удаляет файл из S3 и базы данных. + + **Использование:** + - Удаление ненужных файлов + - Освобождение места в хранилище + - Управление файлами пользователя + + **Безопасность:** + - Пользователь может удалять только свои файлы + - Файл удаляется как из S3, так и из БД + security: + - VkAuth: [] + parameters: + - name: fileId + in: path + required: true + description: "ID файла для удаления" + schema: + type: string + example: "file_abc123" + responses: + '200': + description: Файл успешно удален + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: true + data: + type: object + properties: + message: + type: string + example: "File deleted successfully!" + fileId: + type: string + description: "ID удаленного файла" + timestamp: + type: string + format: date-time + examples: + success: + summary: Успешное удаление + value: + success: true + data: + message: "File deleted successfully!" + fileId: "file_abc123" + timestamp: "2024-01-15T10:30:00Z" + '401': + $ref: '#/components/responses/Unauthorized' + '403': + description: Доступ запрещен + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + access_denied: + summary: Доступ запрещен + value: + error: "Access denied" + '404': + description: Файл не найден + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + not_found: + summary: Файл не найден + value: + error: "File not found" + '500': + $ref: '#/components/responses/InternalError' + +components: + securitySchemes: + ApiKeyAuth: + type: http + scheme: bearer + description: | + API ключ пользователя для доступа к LLM endpoints. + Формат: Bearer sk-... + VkAuth: + type: http + scheme: bearer + description: | + VK подпись для авторизации через VK приложение. + Передается в заголовке Authorization как Bearer token. + + schemas: + Model: + type: object + properties: + id: + type: string + description: "Идентификатор модели" + example: "openai/gpt-4o" + name: + type: string + description: "Название модели" + example: "GPT-4o" + description: + type: string + description: "Описание модели" + example: "Most capable GPT-4 model" + pricing_rub: + type: object + properties: + prompt: + type: number + description: "Цена за входные токены (руб/1K токенов)" + example: 0.15 + completion: + type: number + description: "Цена за выходные токены (руб/1K токенов)" + example: 0.6 + context_length: + type: integer + description: "Максимальная длина контекста" + example: 128000 + created: + type: integer + description: "Время создания модели (Unix timestamp)" + example: 1642234567 + + ChatCompletionRequest: + type: object + required: [messages] + properties: + model: + type: string + default: "google/gemini-2.5-flash-lite" + example: "google/gemini-2.5-flash-lite" + description: | + Модель для генерации ответа. Поддерживаются все модели OpenRouter. + + **Популярные модели:** + - `google/gemini-2.5-flash-lite` - быстрая и дешевая + - `anthropic/claude-3-haiku` - сбалансированная + - `openai/gpt-4o-mini` - OpenAI модель + messages: + type: array + items: + $ref: '#/components/schemas/ChatMessage' + description: "Массив сообщений для контекста" + max_tokens: + type: integer + minimum: 1 + maximum: 32000 + description: "Максимальное количество токенов в ответе" + example: 150 + temperature: + type: number + minimum: 0 + maximum: 2 + description: "Креативность ответа (0.0-2.0)" + example: 0.7 + top_p: + type: number + minimum: 0 + maximum: 1 + description: "Nucleus sampling parameter" + example: 0.9 + frequency_penalty: + type: number + minimum: -2 + maximum: 2 + description: "Штраф за частоту повторений" + example: 0 + presence_penalty: + type: number + minimum: -2 + maximum: 2 + description: "Штраф за присутствие токенов" + example: 0 + stop: + type: array + items: + type: string + description: "Стоп-слова для завершения генерации" + example: ["\n\n", "Human:", "Assistant:"] + stream: + type: boolean + description: "Включить streaming режим" + example: false + + ChatMessage: + type: object + required: [role, content] + properties: + role: + type: string + enum: [system, user, assistant] + description: "Роль отправителя сообщения" + example: "user" + content: + type: string + description: "Содержимое сообщения" + example: "Привет! Как дела?" + + ChatCompletionResponse: + type: object + properties: + id: + type: string + description: "Уникальный идентификатор completion" + example: "chatcmpl-abc123" + object: + type: string + description: "Тип объекта" + example: "chat.completion" + created: + type: integer + description: "Время создания (Unix timestamp)" + example: 1677652288 + model: + type: string + description: "Использованная модель" + example: "google/gemini-2.5-flash-lite" + choices: + type: array + items: + $ref: '#/components/schemas/Choice' + usage: + $ref: '#/components/schemas/Usage' + + Choice: + type: object + properties: + index: + type: integer + description: "Индекс выбора" + example: 0 + message: + $ref: '#/components/schemas/ChatMessage' + finish_reason: + type: string + enum: [stop, length, content_filter, null] + description: "Причина завершения" + example: "stop" + + Usage: + type: object + properties: + prompt_tokens: + type: integer + description: "Количество входных токенов" + example: 4 + completion_tokens: + type: integer + description: "Количество выходных токенов" + example: 147 + total_tokens: + type: integer + description: "Общее количество токенов" + example: 151 + cost: + type: number + description: "Стоимость запроса в рублях" + example: 0.0000592 + + Error: + type: object + properties: + error: + type: string + description: "Описание ошибки" + example: "Invalid request" + + responses: + BadRequest: + description: Неверный запрос + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + missing_messages: + summary: Отсутствует массив messages + value: + error: "messages array is required" + invalid_model: + summary: Неверная модель + value: + error: "Invalid model specified" + + Unauthorized: + description: Неавторизованный доступ + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + invalid_api_key: + summary: Неверный API ключ + value: + error: "Invalid API key or inactive user" + missing_api_key: + summary: Отсутствует API ключ + value: + error: "Missing or invalid Authorization header" + + InternalError: + description: Внутренняя ошибка сервера + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + server_error: + summary: Ошибка сервера + value: + error: "Internal server error" diff --git a/GPTutor-Backend-v2/docs/internal.html b/GPTutor-Backend-v2/docs/internal.html new file mode 100644 index 00000000..e6073d2f --- /dev/null +++ b/GPTutor-Backend-v2/docs/internal.html @@ -0,0 +1,276 @@ + + + + + + GPTutor Internal API Documentation + + + +
+

🔧 GPTutor Internal API

+

Внутренние административные endpoints

+
+ +
+ ВНИМАНИЕ: Этот API предназначен только для внутреннего использования администраторами системы +
+ +
+
+

📋 Обзор API

+

Внутренний API GPTutor предоставляет административные endpoints для управления системой, мониторинга состояния и отладки.

+

Базовый URL: http://localhost:3001 (dev) / https://api.gptutor.site (prod)

+

Версия: 2.0.0

+
+ +
+

🔐 Авторизация

+

VK Auth: Для административных операций требуется VK подпись в заголовке Authorization

+

API Key: Для пользовательских операций требуется API ключ в формате Bearer sk-...

+
+ +

🚀 Доступные Endpoints

+ +
+
+
GET
+
/health
+
+ Проверка состояния сервера. Используется для мониторинга и health checks. +
+
+ +
+
GET
+
/vk-test
+
+ Тест VK авторизации. Отладка VK подписи и получение информации о пользователе. +
+
+ +
+
POST
+
/update-token
+
+ Обновление API токена пользователя. Генерирует новый ключ и делает старый недействительным. +
+
+ +
+
GET
+
/v1/models
+
+ Получение списка доступных AI моделей с информацией о ценах и провайдерах. +
+
+ +
+
POST
+
/v1/chat/completions
+
+ Создание chat completion с поддержкой streaming и автоматическим выбором модели. +
+
+ +
+
POST
+
/upload
+
+ Загрузка файла в S3 с автоматической оптимизацией изображений и сжатием документов. +
+
+ +
+
GET
+
/files
+
+ Получение списка всех файлов пользователя с метаданными. +
+
+ +
+
DELETE
+
/files/:fileId
+
+ Удаление файла из S3 и базы данных. Пользователь может удалять только свои файлы. +
+
+
+ +
+ + +
+
+ + + + diff --git a/GPTutor-Backend-v2/docs/openapi.yaml b/GPTutor-Backend-v2/docs/openapi.yaml new file mode 100644 index 00000000..85a5f8ce --- /dev/null +++ b/GPTutor-Backend-v2/docs/openapi.yaml @@ -0,0 +1,1201 @@ +openapi: 3.0.3 +info: + title: GPTutor Backend v2 API + version: 2.0.0 + description: | + # GPTutor API + + GPTutor предоставляет единый API для доступа к различным AI-моделям через один endpoint. Автоматически обрабатывает fallback'и и выбирает наиболее экономичные варианты. + + ## Быстрый старт + + ### Использование с OpenAI SDK + + **Python:** + ```python + from openai import OpenAI + + client = OpenAI( + base_url="http://localhost:3001/v1", + api_key="your-api-key-here" + ) + + completion = client.chat.completions.create( + model="google/gemini-2.5-flash-lite", + messages=[ + {"role": "user", "content": "Привет! Как дела?"} + ] + ) + + print(completion.choices[0].message.content) + ``` + + **JavaScript:** + ```javascript + import OpenAI from 'openai'; + + const openai = new OpenAI({ + baseURL: 'http://localhost:3001/v1', + apiKey: 'your-api-key-here' + }); + + const completion = await openai.chat.completions.create({ + model: 'google/gemini-2.5-flash-lite', + messages: [ + { role: 'user', content: 'Привет! Как дела?' } + ] + }); + + console.log(completion.choices[0].message.content); + ``` + + ### Прямое использование API + + ```bash + curl -X POST http://localhost:3001/v1/chat/completions \ + -H "Authorization: Bearer your-api-key-here" \ + -H "Content-Type: application/json" \ + -d '{ + "model": "google/gemini-2.5-flash-lite", + "messages": [ + {"role": "user", "content": "Привет!"} + ] + }' + ``` + + ## Streaming + + API поддерживает streaming ответы от любой модели. Это полезно для создания чат-интерфейсов или других приложений, где UI должен обновляться по мере генерации ответа. + + **Python:** + ```python + import requests + import json + + response = requests.post( + 'http://localhost:3001/v1/chat/completions', + headers={'Authorization': 'Bearer your-api-key-here'}, + json={ + 'model': 'google/gemini-2.5-flash-lite', + 'messages': [{'role': 'user', 'content': 'Расскажи историю'}], + 'stream': True + }, + stream=True + ) + + for line in response.iter_lines(): + if line: + line_text = line.decode('utf-8') + if line_text.startswith('data: '): + data = line_text[6:] + if data == '[DONE]': + break + try: + parsed = json.loads(data) + content = parsed['choices'][0]['delta'].get('content') + if content: + print(content, end='', flush=True) + except json.JSONDecodeError: + pass + ``` + + **JavaScript:** + ```javascript + const response = await fetch('http://localhost:3001/v1/chat/completions', { + method: 'POST', + headers: { + 'Authorization': 'Bearer your-api-key-here', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + model: 'google/gemini-2.5-flash-lite', + messages: [{ role: 'user', content: 'Расскажи историю' }], + stream: true + }) + }); + + const reader = response.body.getReader(); + const decoder = new TextDecoder(); + + while (true) { + const { done, value } = await reader.read(); + if (done) break; + + const chunk = decoder.decode(value); + const lines = chunk.split('\n'); + + for (const line of lines) { + if (line.startsWith('data: ')) { + const data = line.slice(6); + if (data === '[DONE]') continue; + + try { + const parsed = JSON.parse(data); + const content = parsed.choices?.[0]?.delta?.content; + if (content) { + process.stdout.write(content); + } + } catch (e) { + // Игнорируем ошибки парсинга + } + } + } + } + ``` + + ## Аутентификация + + API использует Bearer токены для аутентификации. Получите ваш API ключ у администратора системы. + + ```bash + curl -H "Authorization: Bearer your-api-key-here" \ + http://localhost:3001/v1/chat/completions + ``` + + ## Стоимость + + Стоимость рассчитывается автоматически на основе токенов и списывается с баланса пользователя. Информация о стоимости включена в каждый ответ. + + contact: + name: GPTutor Support + url: https://gptutor.site + license: + name: MIT + url: https://opensource.org/licenses/MIT + +servers: + - url: http://localhost:3001 + description: Development server + - url: https://api.openai.com/ + description: Production server + +tags: + - name: Chat Completions + description: OpenAI-совместимые chat completions с поддержкой streaming + - name: Chat Models + description: Управление и получение информации о доступных моделях LLM + - name: Files + description: Управление файлами - загрузка, удаление и получение списка файлов пользователя + +paths: + /v1/chat/completions: + post: + tags: [Chat Completions] + summary: Создание chat completion + description: | + Создание chat completion с поддержкой streaming. + + ## Параметры + + - `model` - модель для генерации (по умолчанию: google/gemini-2.5-flash-lite) + - `messages` - массив сообщений для контекста + - `stream` - включить streaming режим + - `max_tokens` - максимальное количество токенов + - `temperature` - креативность ответа (0.0-1.0) + + ## Streaming + + При `stream: true` ответ приходит в формате Server-Sent Events: + + ``` + data: {"choices":[{"delta":{"content":"Hello"}}]} + data: {"choices":[{"delta":{"content":" there!"}}]} + data: [DONE] + ``` + + ## Стоимость + + Стоимость рассчитывается автоматически и списывается с баланса пользователя. Информация о стоимости включена в каждый ответ. + security: + - ApiKeyAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ChatCompletionRequest' + examples: + simple: + summary: Простой запрос + value: + model: "google/gemini-2.5-flash-lite" + messages: + - role: "user" + content: "Привет! Как дела?" + streaming: + summary: Streaming запрос + value: + model: "google/gemini-2.5-flash-lite" + messages: + - role: "user" + content: "Расскажи историю" + stream: true + max_tokens: 150 + advanced: + summary: Продвинутый запрос + value: + model: "anthropic/claude-3-haiku" + messages: + - role: "user" + content: "Объясни квантовую физику простыми словами" + max_tokens: 500 + temperature: 0.7 + responses: + '200': + description: Успешный ответ + content: + application/json: + schema: + $ref: '#/components/schemas/ChatCompletionResponse' + examples: + non_streaming: + summary: Обычный ответ + value: + id: "chatcmpl-abc123" + object: "chat.completion" + created: 1677652288 + model: "google/gemini-2.5-flash-lite" + choices: + - index: 0 + message: + role: "assistant" + content: "Привет! У меня всё отлично, спасибо!" + finish_reason: "stop" + usage: + prompt_tokens: 4 + completion_tokens: 147 + total_tokens: 151 + cost: 0.0000592 + prompt_tokens_details: + cached_tokens: 0 + audio_tokens: 0 + cost_details: + upstream_inference_completions_cost: 0.0053 + completion_tokens_details: + reasoning_tokens: 0 + image_tokens: 0 + text/event-stream: + schema: + type: string + description: Server-Sent Events для streaming режима + examples: + streaming: + summary: Streaming ответ + value: | + data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1677652288,"model":"google/gemini-2.5-flash-lite","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]} + + data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1677652288,"model":"google/gemini-2.5-flash-lite","choices":[{"index":0,"delta":{"content":"Привет"},"finish_reason":null}]} + + data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1677652288,"model":"google/gemini-2.5-flash-lite","choices":[{"index":0,"delta":{"content":"!"},"finish_reason":null}]} + + data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1677652288,"model":"google/gemini-2.5-flash-lite","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]} + + data: [DONE] + '400': + $ref: '#/components/responses/ValidationError' + '401': + $ref: '#/components/responses/UnauthorizedError' + '402': + $ref: '#/components/responses/InsufficientBalance' + '500': + $ref: '#/components/responses/InternalError' + + /v1/models: + get: + tags: [ChatModels] + summary: Получить список доступных моделей + description: | + Получить список моделей от популярных провайдеров с ценами в рублях. + **Поддерживаемые провайдеры:** x-ai, deepseek, google, qwen, perplexity, mistralai, openai + + ## Ценообразование + + Все цены возвращаются в рублях: + + responses: + '200': + description: Список моделей успешно получен + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: true + data: + type: object + properties: + models: + type: array + items: + $ref: '#/components/schemas/Model' + total: + type: integer + description: Общее количество моделей + example: 45 + providers: + type: array + items: + type: string + description: Список поддерживаемых провайдеров + example: ["x-ai", "deepseek", "google", "qwen", "perplexity", "mistralai", "openai"] + lastUpdated: + type: string + format: date-time + description: Время последнего обновления + example: "2025-01-28T10:30:00.000Z" + examples: + success: + summary: Успешный ответ + value: + success: true + data: + models: + - id: "google/gemini-2.5-flash-lite-preview-09-2025" + name: "Google: Gemini 2.5 Flash Lite Preview 09-2025" + description: "Gemini 2.5 Flash-Lite is a lightweight reasoning model..." + context_length: 1048576 + pricing_rub: + prompt: 0.000009 + completion: 0.000036 + request: 0 + image: 0 + web_search: 0 + internal_reasoning: 0 + + total: 45 + providers: ["x-ai", "deepseek", "google", "qwen", "perplexity", "mistralai", "openai"] + lastUpdated: "2025-01-28T10:30:00.000Z" + '503': + description: Сервис моделей не готов + content: + application/json: + schema: + type: object + properties: + error: + type: string + example: "Models service not ready" + '500': + $ref: '#/components/responses/InternalError' + + /vk-test: + get: + tags: [Authentication] + summary: Тест VK авторизации + description: | + Тестирует VK авторизацию и возвращает информацию о пользователе. + + Требует VK подпись в заголовке Authorization. + security: + - VkAuth: [] + responses: + '200': + description: Успешная авторизация + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: true + data: + type: object + properties: + message: + type: string + example: "VK authorization successful!" + vkData: + type: object + description: "Данные от VK" + dbUser: + type: object + properties: + id: + type: string + vkId: + type: string + balance: + type: number + apiKey: + type: string + isActive: + type: boolean + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + timestamp: + type: string + format: date-time + '401': + $ref: '#/components/responses/Unauthorized' + '500': + $ref: '#/components/responses/InternalError' + + /update-token: + post: + tags: [Authentication] + summary: Обновление API токена + description: | + Генерирует новый API ключ для пользователя. Старый ключ становится недействительным. + + Требует VK авторизацию. + security: + - VkAuth: [] + responses: + '200': + description: Токен успешно обновлен + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: true + data: + type: object + properties: + message: + type: string + example: "API token updated successfully!" + newApiKey: + type: string + description: "Новый API ключ" + example: "sk-abc123..." + user: + type: object + properties: + id: + type: string + vkId: + type: string + balance: + type: number + isActive: + type: boolean + updatedAt: + type: string + format: date-time + timestamp: + type: string + format: date-time + examples: + success: + summary: Успешное обновление токена + value: + success: true + data: + message: "API token updated successfully!" + newApiKey: "sk-abc123def456ghi789jkl012mno345pqr678stu901vwx234yz567890" + user: + id: "user_123" + vkId: "vk_456" + balance: 10.5 + isActive: true + updatedAt: "2024-01-15T10:30:00Z" + timestamp: "2024-01-15T10:30:00Z" + '401': + $ref: '#/components/responses/Unauthorized' + '500': + $ref: '#/components/responses/InternalError' + + /upload: + post: + tags: [Files] + summary: Загрузить файл + description: | + Загружает файл в облачное хранилище Yandex S3 с автоматической оптимизацией. + + ## Поддерживаемые типы файлов + + ### Изображения + - JPG, JPEG, PNG, GIF, BMP, SVG, WebP, TIFF, TIF + - Автоматически оптимизируются (качество 60%) + + ### Документы + - PDF (сжатие) + - DOC, DOCX, XLS, XLSX, CSV + + ### Текстовые файлы + - TXT, JS, HTML, CSS, JSON, XML, MD, LOG + - PY, JAVA, C, CPP, H, SH, CONFIG, CONF, INI + - YML, YAML, SQL + + ## Ограничения + + - Максимальный размер файла: 50MB + - Требует VK авторизацию + - Файлы автоматически оптимизируются и сжимаются + + ## Ответ + + Возвращает информацию о загруженном файле включая URL для доступа. + security: + - VkAuth: [] + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + file: + type: string + format: binary + description: Файл для загрузки + examples: + image: + summary: Загрузка изображения + value: + file: "[binary data]" + document: + summary: Загрузка документа + value: + file: "[binary data]" + responses: + '200': + description: Файл успешно загружен + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: true + data: + type: object + properties: + message: + type: string + example: "File uploaded successfully!" + file: + $ref: '#/components/schemas/FileInfo' + timestamp: + type: string + format: date-time + examples: + success: + summary: Успешная загрузка + value: + success: true + data: + message: "File uploaded successfully!" + file: + id: "file_123" + name: "document.pdf" + type: "application/pdf" + url: "https://gptutor-bucket.storage.yandexcloud.net/uuid.pdf" + size: 1024000 + createdAt: "2024-01-15T10:30:00Z" + timestamp: "2024-01-15T10:30:00Z" + '400': + description: Ошибка валидации + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: false + error: + type: string + examples: + - "No file provided" + - "Unsupported file type" + - "Invalid filename" + - "File too large. Maximum size is 50MB" + '401': + $ref: '#/components/responses/Unauthorized' + '413': + description: Файл слишком большой + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: false + error: + type: string + example: "File too large. Maximum size is 50MB" + '500': + $ref: '#/components/responses/InternalError' + + /files: + get: + tags: [Files] + summary: Получить список файлов пользователя + description: | + Возвращает список всех файлов, загруженных пользователем. + + ## Возвращаемые данные + + - Список файлов с метаданными + - Общее количество файлов + - Информация о каждом файле (ID, имя, тип, URL, размер, дата создания) + security: + - VkAuth: [] + responses: + '200': + description: Список файлов успешно получен + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: true + data: + type: object + properties: + message: + type: string + example: "Files retrieved successfully!" + files: + type: array + items: + $ref: '#/components/schemas/FileInfo' + total: + type: integer + example: 5 + timestamp: + type: string + format: date-time + examples: + success: + summary: Список файлов + value: + success: true + data: + message: "Files retrieved successfully!" + files: + - id: "file_123" + name: "document.pdf" + type: "application/pdf" + url: "https://gptutor-bucket.storage.yandexcloud.net/uuid.pdf" + size: 1024000 + createdAt: "2024-01-15T10:30:00Z" + - id: "file_456" + name: "image.jpg" + type: "image/jpeg" + url: "https://gptutor-bucket.storage.yandexcloud.net/uuid.jpg" + size: 512000 + createdAt: "2024-01-15T09:15:00Z" + total: 2 + timestamp: "2024-01-15T10:30:00Z" + '401': + $ref: '#/components/responses/Unauthorized' + '500': + $ref: '#/components/responses/InternalError' + + /files/{fileId}: + delete: + tags: [Files] + summary: Удалить файл + description: | + Удаляет файл по его ID. Файл удаляется как из облачного хранилища, так и из базы данных. + + ## Ограничения + + - Можно удалять только свои файлы + - Требует VK авторизацию + - Файл должен существовать + + ## Параметры + + - `fileId` - ID файла для удаления + security: + - VkAuth: [] + parameters: + - name: fileId + in: path + required: true + description: ID файла для удаления + schema: + type: string + example: "file_123" + responses: + '200': + description: Файл успешно удален + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: true + data: + type: object + properties: + message: + type: string + example: "File deleted successfully!" + fileId: + type: string + example: "file_123" + timestamp: + type: string + format: date-time + examples: + success: + summary: Успешное удаление + value: + success: true + data: + message: "File deleted successfully!" + fileId: "file_123" + timestamp: "2024-01-15T10:30:00Z" + '401': + $ref: '#/components/responses/Unauthorized' + '403': + description: Доступ запрещен + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: false + error: + type: string + example: "Access denied" + '404': + description: Файл не найден + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: false + error: + type: string + example: "File not found" + '500': + $ref: '#/components/responses/InternalError' + +components: + securitySchemes: + ApiKeyBearer: + type: http + scheme: bearer + description: | + API ключ пользователя для доступа к LLM endpoints. + VkAuth: + type: http + scheme: bearer + description: | + VK подпись для авторизации через VK приложение. + Передается в заголовке Authorization как Bearer token. + + schemas: + ChatCompletionRequest: + type: object + required: [messages] + properties: + model: + type: string + default: "google/gemini-2.5-flash-lite" + example: "google/gemini-2.5-flash-lite" + description: | + Модель для генерации ответа. Поддерживаются все модели OpenRouter. + + **Популярные модели:** + - `google/gemini-2.5-flash-lite` - быстрая и дешевая + - `anthropic/claude-3-haiku` - сбалансированная + - `openai/gpt-4o-mini` - OpenAI модель + messages: + type: array + items: + $ref: '#/components/schemas/ChatMessage' + example: + - role: "user" + content: "Привет!" + max_tokens: + type: integer + minimum: 1 + maximum: 4000 + example: 150 + description: Максимальное количество токенов в ответе + temperature: + type: number + minimum: 0 + maximum: 2 + example: 0.7 + description: Креативность ответа (0 = детерминированный, 2 = очень креативный) + top_p: + type: number + minimum: 0 + maximum: 1 + example: 0.9 + description: Nucleus sampling параметр + frequency_penalty: + type: number + minimum: -2 + maximum: 2 + example: 0 + description: Штраф за повторение слов + presence_penalty: + type: number + minimum: -2 + maximum: 2 + example: 0 + description: Штраф за повторение тем + stop: + type: array + items: + type: string + example: ["\n", "###"] + description: Стоп-последовательности для завершения генерации + stream: + type: boolean + default: false + example: true + description: Включить streaming режим (Server-Sent Events) + + ChatMessage: + type: object + required: [role, content] + properties: + role: + type: string + enum: [system, user, assistant] + example: "user" + description: | + Роль отправителя сообщения: + - `system` - системные инструкции для AI + - `user` - сообщения пользователя + - `assistant` - ответы AI + content: + type: string + example: "Привет! Как дела?" + description: Текст сообщения + + ChatCompletionResponse: + type: object + properties: + id: + type: string + example: "chatcmpl-abc123" + object: + type: string + example: "chat.completion" + created: + type: integer + example: 1677652288 + model: + type: string + example: "google/gemini-2.5-flash-lite" + choices: + type: array + items: + $ref: '#/components/schemas/ChatChoice' + usage: + $ref: '#/components/schemas/Usage' + + ChatChoice: + type: object + properties: + index: + type: integer + example: 0 + message: + $ref: '#/components/schemas/ChatMessage' + finish_reason: + type: string + enum: [stop, length, content_filter] + example: "stop" + + Usage: + type: object + description: | + Информация об использовании токенов и стоимости. + + **Структура ответа:** + - `prompt_tokens` - токены запроса + - `completion_tokens` - токены ответа + - `total_tokens` - всего токенов + - `cost` - цена в долларах + - `cost_details.upstream_inference_completions_cost` - цена в рублях + - `prompt_tokens_details` - детали токенов запроса + - `completion_tokens_details` - детали токенов ответа + properties: + prompt_tokens: + type: integer + example: 4 + description: Количество токенов в запросе + completion_tokens: + type: integer + example: 147 + description: Количество токенов в ответе + total_tokens: + type: integer + example: 151 + description: Общее количество токенов + cost: + type: number + format: float + example: 0.0000592 + description: Стоимость запроса в долларах + prompt_tokens_details: + type: object + properties: + cached_tokens: + type: integer + example: 0 + description: Количество кешированных токенов + audio_tokens: + type: integer + example: 0 + description: Количество аудио токенов + cost_details: + type: object + properties: + upstream_inference_completions_cost: + type: number + format: float + example: 0.0053 + description: Стоимость запроса в рублях + completion_tokens_details: + type: object + properties: + reasoning_tokens: + type: integer + example: 0 + description: Количество токенов рассуждения + image_tokens: + type: integer + example: 0 + description: Количество токенов изображений + + Error: + type: object + properties: + error: + type: string + example: "Invalid API key" + + Model: + type: object + description: Модель LLM с ценами в рублях + properties: + id: + type: string + description: Уникальный идентификатор модели + example: "google/gemini-2.5-flash-lite-preview-09-2025" + canonical_slug: + type: string + description: Канонический слаг модели + example: "google/gemini-2.5-flash-lite-preview-09-2025" + hugging_face_id: + type: string + description: ID модели в Hugging Face + example: "" + name: + type: string + description: Человекочитаемое название модели + example: "Google: Gemini 2.5 Flash Lite Preview 09-2025" + created: + type: integer + description: Unix timestamp создания модели + example: 1758819686 + description: + type: string + description: Описание модели + example: "Gemini 2.5 Flash-Lite is a lightweight reasoning model..." + context_length: + type: integer + description: Максимальная длина контекста + example: 1048576 + architecture: + type: object + description: Архитектура модели + properties: + modality: + type: string + example: "text+image->text" + input_modalities: + type: array + items: + type: string + example: ["file", "image", "text", "audio"] + output_modalities: + type: array + items: + type: string + example: ["text"] + tokenizer: + type: string + example: "Gemini" + instruct_type: + type: string + nullable: true + example: null + pricing_rub: + type: object + description: Цены в рублях + properties: + prompt: + type: number + description: Цена за входной токен + example: 0.000009 + completion: + type: number + description: Цена за выходной токен + example: 0.000036 + request: + type: number + description: Фиксированная цена за запрос + example: 0 + image: + type: number + description: Цена за изображение + example: 0 + web_search: + type: number + description: Цена за веб-поиск + example: 0 + internal_reasoning: + type: number + description: Цена за внутренние рассуждения + example: 0 + top_provider: + type: object + description: Информация о топ-провайдере + properties: + context_length: + type: integer + example: 1048576 + max_completion_tokens: + type: integer + example: 65536 + is_moderated: + type: boolean + example: false + supported_parameters: + type: array + items: + type: string + description: Поддерживаемые параметры + example: ["include_reasoning", "max_tokens", "reasoning", "response_format", "seed", "stop", "structured_outputs", "temperature", "tool_choice", "tools", "top_p"] + default_parameters: + type: object + description: Параметры по умолчанию + properties: + temperature: + type: number + nullable: true + top_p: + type: number + nullable: true + frequency_penalty: + type: number + nullable: true + + FileInfo: + type: object + description: Информация о файле + properties: + id: + type: string + description: Уникальный идентификатор файла + example: "file_123" + name: + type: string + description: Оригинальное имя файла + example: "document.pdf" + type: + type: string + description: MIME-тип файла + example: "application/pdf" + url: + type: string + description: URL для доступа к файлу в облачном хранилище + example: "https://gptutor-bucket.storage.yandexcloud.net/uuid.pdf" + size: + type: integer + description: Размер файла в байтах + example: 1024000 + createdAt: + type: string + format: date-time + description: Дата и время загрузки файла + example: "2024-01-15T10:30:00Z" + + responses: + UnauthorizedError: + description: Ошибка авторизации + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + invalid_api_key: + summary: Неверный API ключ + value: + error: "Invalid API key or inactive user" + missing_api_key: + summary: Отсутствует API ключ + value: + error: "Missing or invalid Authorization header" + + Unauthorized: + description: Ошибка VK авторизации + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + invalid_vk_auth: + summary: Неверная VK авторизация + value: + error: "Invalid VK authorization" + + ValidationError: + description: Ошибка валидации + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + missing_messages: + summary: Отсутствует массив messages + value: + error: "messages array is required" + + InsufficientBalance: + description: Недостаточно средств + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + low_balance: + summary: Недостаточно средств + value: + error: "Insufficient balance" + + InternalError: + description: Внутренняя ошибка сервера + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + server_error: + summary: Ошибка сервера + value: + error: "Internal server error" diff --git a/GPTutor-Backend-v2/docs/package-lock.json b/GPTutor-Backend-v2/docs/package-lock.json new file mode 100644 index 00000000..984d1fdc --- /dev/null +++ b/GPTutor-Backend-v2/docs/package-lock.json @@ -0,0 +1,1212 @@ +{ + "name": "gptutor-internal-docs", + "version": "2.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "gptutor-internal-docs", + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "express": "^4.18.2" + }, + "devDependencies": { + "nodemon": "^3.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "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==", + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", + "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.13.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/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "license": "MIT", + "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/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", + "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==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "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, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "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/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "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, + "license": "MIT", + "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==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "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==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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==", + "license": "MIT", + "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/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "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, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/nodemon": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz", + "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/nodemon/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, + "license": "MIT" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "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/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "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" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "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/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "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, + "license": "MIT", + "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==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + } + } +} diff --git a/GPTutor-Backend-v2/docs/package.json b/GPTutor-Backend-v2/docs/package.json new file mode 100644 index 00000000..c0fe9ad2 --- /dev/null +++ b/GPTutor-Backend-v2/docs/package.json @@ -0,0 +1,32 @@ +{ + "name": "gptutor-internal-docs", + "version": "2.0.0", + "description": "Внутренняя документация API для GPTutor", + "main": "serve-internal.js", + "scripts": { + "start": "node serve-internal.js", + "dev": "nodemon serve-internal.js", + "serve": "node serve-internal.js" + }, + "dependencies": { + "express": "^4.18.2" + }, + "devDependencies": { + "nodemon": "^3.0.1" + }, + "keywords": [ + "gptutor", + "api", + "documentation", + "internal", + "openapi", + "scalar" + ], + "author": "GPTutor Team", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } +} + + diff --git a/GPTutor-Backend-v2/docs/serve-internal.js b/GPTutor-Backend-v2/docs/serve-internal.js new file mode 100644 index 00000000..c8d49585 --- /dev/null +++ b/GPTutor-Backend-v2/docs/serve-internal.js @@ -0,0 +1,79 @@ +const express = require("express"); +const path = require("path"); +const fs = require("fs"); + +const app = express(); +const PORT = 3002; + +app.use((req, res, next) => { + console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`); + next(); +}); + +app.use(express.static(path.join(__dirname))); + +app.get("/", (req, res) => { + res.redirect("/internal.html"); +}); + +app.get("/internal-api.yaml", (req, res) => { + const yamlPath = path.join(__dirname, "internal-api.yaml"); + + if (fs.existsSync(yamlPath)) { + res.setHeader("Content-Type", "application/x-yaml"); + res.setHeader("Access-Control-Allow-Origin", "*"); + res.sendFile(yamlPath); + } else { + res.status(404).send("OpenAPI specification not found"); + } +}); + +app.get("/health", (req, res) => { + res.json({ + status: "ok", + service: "GPTutor Internal Documentation Server", + timestamp: new Date().toISOString(), + version: "2.0.0", + }); +}); + +app.use((err, req, res, next) => { + console.error("Error:", err); + res.status(500).json({ + error: "Internal server error", + message: err.message, + }); +}); + +app.use((req, res) => { + res.status(404).json({ + error: "Not found", + message: `Route ${req.method} ${req.url} not found`, + }); +}); + +app.listen(PORT, () => { + console.log("🚀 GPTutor Internal Documentation Server запущен!"); + console.log(`📖 Документация доступна по адресу: http://localhost:${PORT}`); + console.log(`🔧 Health check: http://localhost:${PORT}/health`); + console.log(`📋 OpenAPI spec: http://localhost:${PORT}/internal-api.yaml`); + console.log(""); + console.log("Доступные endpoints:"); + console.log(" GET / - Главная страница"); + console.log(" GET /internal.html - Внутренняя документация"); + console.log(" GET /internal-api.yaml - OpenAPI спецификация"); + console.log(" GET /health - Health check"); + console.log(""); + console.log("Для остановки сервера нажмите Ctrl+C"); +}); + +// Graceful shutdown +process.on("SIGINT", () => { + console.log("\n🛑 Получен сигнал SIGINT, завершение работы..."); + process.exit(0); +}); + +process.on("SIGTERM", () => { + console.log("\n🛑 Получен сигнал SIGTERM, завершение работы..."); + process.exit(0); +}); diff --git a/GPTutor-Backend-v2/docs/serve.js b/GPTutor-Backend-v2/docs/serve.js new file mode 100644 index 00000000..2ad5644b --- /dev/null +++ b/GPTutor-Backend-v2/docs/serve.js @@ -0,0 +1,84 @@ +const http = require("http"); +const fs = require("fs"); +const path = require("path"); + +const port = 8080; +const docsDir = __dirname; + +const mimeTypes = { + ".html": "text/html", + ".yaml": "text/yaml", + ".yml": "text/yaml", + ".css": "text/css", + ".js": "application/javascript", + ".json": "application/json", + ".png": "image/png", + ".jpg": "image/jpeg", + ".gif": "image/gif", + ".svg": "image/svg+xml", + ".ico": "image/x-icon", +}; + +const server = http.createServer((req, res) => { + res.setHeader("Access-Control-Allow-Origin", "*"); + res.setHeader( + "Access-Control-Allow-Methods", + "GET, POST, PUT, DELETE, OPTIONS" + ); + res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization"); + + if (req.method === "OPTIONS") { + res.writeHead(200); + res.end(); + return; + } + + let filePath = path.join(docsDir, req.url === "/" ? "index.html" : req.url); + + if (!filePath.startsWith(docsDir)) { + res.writeHead(403); + res.end("Forbidden"); + return; + } + + const extname = path.extname(filePath); + const contentType = mimeTypes[extname] || "application/octet-stream"; + + fs.readFile(filePath, (err, content) => { + res.writeHead(200, { "Content-Type": contentType }); + res.end(content, "utf-8"); + }); +}); + +server.listen(port, () => { + console.log("🎉 GPTutor API Documentation Server"); + console.log(`🚀 Server running at http://localhost:${port}`); + console.log(""); + console.log("📋 Available pages:"); + console.log(` 🏠 Welcome page: http://localhost:${port}/`); + console.log(` 📖 API Docs (Light): http://localhost:${port}/index.html`); + console.log(` 🌙 API Docs (Dark): http://localhost:${port}/dark.html`); + console.log( + ` 🧪 Interactive Test: http://localhost:${port}/test-examples.html` + ); + console.log(` 📄 OpenAPI Spec: http://localhost:${port}/openapi.yaml`); + console.log( + ` 📚 Detailed Guide: http://localhost:${port}/CHAT_COMPLETIONS_API.md` + ); + console.log(""); + console.log("✨ Features:"); + console.log(" • Beautiful Scalar UI with light/dark themes"); + console.log(" • Interactive Try-it functionality"); + console.log(" • Comprehensive API documentation"); + console.log(" • Real-time testing interface"); + console.log(""); + console.log("Press Ctrl+C to stop"); +}); + +process.on("SIGINT", () => { + console.log("\n👋 Shutting down documentation server..."); + server.close(() => { + console.log("✅ Server stopped"); + process.exit(0); + }); +}); diff --git a/GPTutor-Backend-v2/logs/.gitignore b/GPTutor-Backend-v2/logs/.gitignore new file mode 100644 index 00000000..95fe8518 --- /dev/null +++ b/GPTutor-Backend-v2/logs/.gitignore @@ -0,0 +1,8 @@ +# Ignore all log files +*.log +*.log.* + +# Keep the directory +!.gitignore + + diff --git a/GPTutor-Backend-v2/nodemon.json b/GPTutor-Backend-v2/nodemon.json new file mode 100644 index 00000000..a883ee5f --- /dev/null +++ b/GPTutor-Backend-v2/nodemon.json @@ -0,0 +1,7 @@ +{ + "watch": ["src"], + "ext": "ts,json", + "ignore": ["src/**/*.spec.ts"], + "exec": "ts-node src/index.ts" +} + diff --git a/GPTutor-Backend-v2/package-lock.json b/GPTutor-Backend-v2/package-lock.json new file mode 100644 index 00000000..879d93d0 --- /dev/null +++ b/GPTutor-Backend-v2/package-lock.json @@ -0,0 +1,3042 @@ +{ + "name": "gptutor-backend-v2", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "gptutor-backend-v2", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@fastify/cors": "^10.0.1", + "@fastify/helmet": "^12.0.1", + "@fastify/jwt": "^9.0.1", + "@fastify/multipart": "^9.0.1", + "@fastify/rate-limit": "^10.1.1", + "@fastify/static": "^8.0.1", + "@fastify/swagger": "^9.1.0", + "@fastify/swagger-ui": "^5.0.1", + "@prisma/client": "^6.16.2", + "@types/uuid": "^10.0.0", + "@types/winston": "^2.4.4", + "crypto-js": "^4.2.0", + "fastify": "^5.1.0", + "openai": "^5.23.1", + "uuid": "^13.0.0", + "winston": "^3.17.0", + "winston-daily-rotate-file": "^5.0.0" + }, + "devDependencies": { + "@types/crypto-js": "^4.2.2", + "@types/node": "^22.10.5", + "node-fetch": "^3.3.2", + "nodemon": "^3.1.9", + "prisma": "^6.16.2", + "ts-node": "^10.9.2", + "typescript": "^5.7.3" + } + }, + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "license": "MIT", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "node_modules/@fastify/accept-negotiator": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@fastify/accept-negotiator/-/accept-negotiator-2.0.1.tgz", + "integrity": "sha512-/c/TW2bO/v9JeEgoD/g1G5GxGeCF1Hafdf79WPmUlgYiBXummY0oX3VVq4yFkKKVBKDNlaDUYoab7g38RpPqCQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/@fastify/ajv-compiler": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-4.0.2.tgz", + "integrity": "sha512-Rkiu/8wIjpsf46Rr+Fitd3HRP+VsxUFDDeag0hs9L0ksfnwx2g7SPQQTFL0E8Qv+rfXzQOxBJnjUB9ITUDjfWQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "ajv": "^8.12.0", + "ajv-formats": "^3.0.1", + "fast-uri": "^3.0.0" + } + }, + "node_modules/@fastify/busboy": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-3.2.0.tgz", + "integrity": "sha512-m9FVDXU3GT2ITSe0UaMA5rU3QkfC/UXtCU8y0gSN/GugTqtVldOBWIB5V6V3sbmenVZUIpU6f+mPEO2+m5iTaA==", + "license": "MIT" + }, + "node_modules/@fastify/cors": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@fastify/cors/-/cors-10.1.0.tgz", + "integrity": "sha512-MZyBCBJtII60CU9Xme/iE4aEy8G7QpzGR8zkdXZkDFt7ElEMachbE61tfhAG/bvSaULlqlf0huMT12T7iqEmdQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "fastify-plugin": "^5.0.0", + "mnemonist": "0.40.0" + } + }, + "node_modules/@fastify/deepmerge": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@fastify/deepmerge/-/deepmerge-3.1.0.tgz", + "integrity": "sha512-lCVONBQINyNhM6LLezB6+2afusgEYR4G8xenMsfe+AT+iZ7Ca6upM5Ha8UkZuYSnuMw3GWl/BiPXnLMi/gSxuQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/@fastify/error": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@fastify/error/-/error-4.2.0.tgz", + "integrity": "sha512-RSo3sVDXfHskiBZKBPRgnQTtIqpi/7zhJOEmAxCiBcM7d0uwdGdxLlsCaLzGs8v8NnxIRlfG0N51p5yFaOentQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/@fastify/fast-json-stringify-compiler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-5.0.3.tgz", + "integrity": "sha512-uik7yYHkLr6fxd8hJSZ8c+xF4WafPK+XzneQDPU+D10r5X19GW8lJcom2YijX2+qtFF1ENJlHXKFM9ouXNJYgQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "fast-json-stringify": "^6.0.0" + } + }, + "node_modules/@fastify/forwarded": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@fastify/forwarded/-/forwarded-3.0.0.tgz", + "integrity": "sha512-kJExsp4JCms7ipzg7SJ3y8DwmePaELHxKYtg+tZow+k0znUTf3cb+npgyqm8+ATZOdmfgfydIebPDWM172wfyA==", + "license": "MIT" + }, + "node_modules/@fastify/helmet": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/@fastify/helmet/-/helmet-12.0.1.tgz", + "integrity": "sha512-kkjBcedWwdflRThovGuvN9jB2QQLytBqArCFPdMIb7o2Fp0l/H3xxYi/6x/SSRuH/FFt9qpTGIfJz2bfnMrLqA==", + "license": "MIT", + "dependencies": { + "fastify-plugin": "^5.0.0", + "helmet": "^7.1.0" + } + }, + "node_modules/@fastify/jwt": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@fastify/jwt/-/jwt-9.1.0.tgz", + "integrity": "sha512-CiGHCnS5cPMdb004c70sUWhQTfzrJHAeTywt7nVw6dAiI0z1o4WRvU94xfijhkaId4bIxTCOjFgn4sU+Gvk43w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "@fastify/error": "^4.0.0", + "@lukeed/ms": "^2.0.2", + "fast-jwt": "^5.0.0", + "fastify-plugin": "^5.0.0", + "steed": "^1.1.3" + } + }, + "node_modules/@fastify/merge-json-schemas": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@fastify/merge-json-schemas/-/merge-json-schemas-0.2.1.tgz", + "integrity": "sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/@fastify/multipart": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@fastify/multipart/-/multipart-9.2.1.tgz", + "integrity": "sha512-U4221XDMfzCUtfzsyV1/PkR4MNgKI0158vUUyn/oF2Tl6RxMc+N7XYLr5fZXQiEC+Fmw5zFaTjxsTGTgtDtK+g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "@fastify/busboy": "^3.0.0", + "@fastify/deepmerge": "^3.0.0", + "@fastify/error": "^4.0.0", + "fastify-plugin": "^5.0.0", + "secure-json-parse": "^4.0.0" + } + }, + "node_modules/@fastify/proxy-addr": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@fastify/proxy-addr/-/proxy-addr-5.0.0.tgz", + "integrity": "sha512-37qVVA1qZ5sgH7KpHkkC4z9SK6StIsIcOmpjvMPXNb3vx2GQxhZocogVYbr2PbbeLCQxYIPDok307xEvRZOzGA==", + "license": "MIT", + "dependencies": { + "@fastify/forwarded": "^3.0.0", + "ipaddr.js": "^2.1.0" + } + }, + "node_modules/@fastify/rate-limit": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@fastify/rate-limit/-/rate-limit-10.3.0.tgz", + "integrity": "sha512-eIGkG9XKQs0nyynatApA3EVrojHOuq4l6fhB4eeCk4PIOeadvOJz9/4w3vGI44Go17uaXOWEcPkaD8kuKm7g6Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "@lukeed/ms": "^2.0.2", + "fastify-plugin": "^5.0.0", + "toad-cache": "^3.7.0" + } + }, + "node_modules/@fastify/send": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@fastify/send/-/send-4.1.0.tgz", + "integrity": "sha512-TMYeQLCBSy2TOFmV95hQWkiTYgC/SEx7vMdV+wnZVX4tt8VBLKzmH8vV9OzJehV0+XBfg+WxPMt5wp+JBUKsVw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "@lukeed/ms": "^2.0.2", + "escape-html": "~1.0.3", + "fast-decode-uri-component": "^1.0.1", + "http-errors": "^2.0.0", + "mime": "^3" + } + }, + "node_modules/@fastify/static": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@fastify/static/-/static-8.2.0.tgz", + "integrity": "sha512-PejC/DtT7p1yo3p+W7LiUtLMsV8fEvxAK15sozHy9t8kwo5r0uLYmhV/inURmGz1SkHZFz/8CNtHLPyhKcx4SQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "@fastify/accept-negotiator": "^2.0.0", + "@fastify/send": "^4.0.0", + "content-disposition": "^0.5.4", + "fastify-plugin": "^5.0.0", + "fastq": "^1.17.1", + "glob": "^11.0.0" + } + }, + "node_modules/@fastify/swagger": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/@fastify/swagger/-/swagger-9.5.2.tgz", + "integrity": "sha512-8e8w/LItg/cF6IR/hYKtnt+E0QImees5o3YWJsTLxaIk+tzNUEc6Z2Ursi4oOHWwUlKjUCnV6yh5z5ZdxvlsWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "fastify-plugin": "^5.0.0", + "json-schema-resolver": "^3.0.0", + "openapi-types": "^12.1.3", + "rfdc": "^1.3.1", + "yaml": "^2.4.2" + } + }, + "node_modules/@fastify/swagger-ui": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@fastify/swagger-ui/-/swagger-ui-5.2.3.tgz", + "integrity": "sha512-e7ivEJi9EpFcxTONqICx4llbpB2jmlI+LI1NQ/mR7QGQnyDOqZybPK572zJtcdHZW4YyYTBHcP3a03f1pOh0SA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "@fastify/static": "^8.0.0", + "fastify-plugin": "^5.0.0", + "openapi-types": "^12.1.3", + "rfdc": "^1.3.1", + "yaml": "^2.4.1" + } + }, + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, + "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==", + "license": "ISC", + "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/@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, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@lukeed/ms": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@lukeed/ms/-/ms-2.0.2.tgz", + "integrity": "sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@prisma/client": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.16.2.tgz", + "integrity": "sha512-E00PxBcalMfYO/TWnXobBVUai6eW/g5OsifWQsQDzJYm7yaY+IRLo7ZLsaefi0QkTpxfuhFcQ/w180i6kX3iJw==", + "hasInstallScript": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "prisma": "*", + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@prisma/config": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.16.2.tgz", + "integrity": "sha512-mKXSUrcqXj0LXWPmJsK2s3p9PN+aoAbyMx7m5E1v1FufofR1ZpPoIArjjzOIm+bJRLLvYftoNYLx1tbHgF9/yg==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "c12": "3.1.0", + "deepmerge-ts": "7.1.5", + "effect": "3.16.12", + "empathic": "2.0.0" + } + }, + "node_modules/@prisma/debug": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.16.2.tgz", + "integrity": "sha512-bo4/gA/HVV6u8YK2uY6glhNsJ7r+k/i5iQ9ny/3q5bt9ijCj7WMPUwfTKPvtEgLP+/r26Z686ly11hhcLiQ8zA==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/engines": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.16.2.tgz", + "integrity": "sha512-7yf3AjfPUgsg/l7JSu1iEhsmZZ/YE00yURPjTikqm2z4btM0bCl2coFtTGfeSOWbQMmq45Jab+53yGUIAT1sjA==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.16.2", + "@prisma/engines-version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", + "@prisma/fetch-engine": "6.16.2", + "@prisma/get-platform": "6.16.2" + } + }, + "node_modules/@prisma/engines-version": { + "version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43.tgz", + "integrity": "sha512-ThvlDaKIVrnrv97ujNFDYiQbeMQpLa0O86HFA2mNoip4mtFqM7U5GSz2ie1i2xByZtvPztJlNRgPsXGeM/kqAA==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/fetch-engine": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.16.2.tgz", + "integrity": "sha512-wPnZ8DMRqpgzye758ZvfAMiNJRuYpz+rhgEBZi60ZqDIgOU2694oJxiuu3GKFeYeR/hXxso4/2oBC243t/whxQ==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.16.2", + "@prisma/engines-version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", + "@prisma/get-platform": "6.16.2" + } + }, + "node_modules/@prisma/get-platform": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.16.2.tgz", + "integrity": "sha512-U/P36Uke5wS7r1+omtAgJpEB94tlT4SdlgaeTc6HVTTT93pXj7zZ+B/cZnmnvjcNPfWddgoDx8RLjmQwqGDYyA==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.16.2" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/crypto-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz", + "integrity": "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.18.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.6.tgz", + "integrity": "sha512-r8uszLPpeIWbNKtvWRt/DbVi5zbqZyj1PTmhRMqBMvDnaz1QpmSKujUtJLrqGZeoM8v72MfYggDceY4K1itzWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", + "license": "MIT" + }, + "node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "license": "MIT" + }, + "node_modules/@types/winston": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/winston/-/winston-2.4.4.tgz", + "integrity": "sha512-BVGCztsypW8EYwJ+Hq+QNYiT/MUyCif0ouBH+flrY66O5W+KIXAMML6E/0fJpm7VjIzgangahl5S03bJJQGrZw==", + "deprecated": "This is a stub types definition. winston provides its own type definitions, so you do not need this installed.", + "license": "MIT", + "dependencies": { + "winston": "*" + } + }, + "node_modules/abstract-logging": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", + "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==", + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "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==", + "license": "MIT", + "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": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "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, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "license": "MIT" + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/avvio": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/avvio/-/avvio-9.1.0.tgz", + "integrity": "sha512-fYASnYi600CsH/j9EQov7lECAniYiBFiiAtBNuZYLA2leLe9qOvZzqYHFjtIj6gD2VMoMLP14834LFWvr4IfDw==", + "license": "MIT", + "dependencies": { + "@fastify/error": "^4.0.0", + "fastq": "^1.17.1" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/c12": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz", + "integrity": "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.3", + "confbox": "^0.2.2", + "defu": "^6.1.4", + "dotenv": "^16.6.1", + "exsolve": "^1.0.7", + "giget": "^2.0.0", + "jiti": "^2.4.2", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^1.0.0", + "pkg-types": "^2.2.0", + "rc9": "^2.1.2" + }, + "peerDependencies": { + "magicast": "^0.3.5" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, + "node_modules/c12/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/c12/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "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, + "license": "MIT", + "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/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + } + }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/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==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/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==", + "license": "MIT" + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "license": "MIT", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, + "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, + "license": "MIT" + }, + "node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", + "license": "MIT" + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deepmerge-ts": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", + "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", + "devOptional": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "devOptional": true, + "license": "MIT" + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "devOptional": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/effect": { + "version": "3.16.12", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.16.12.tgz", + "integrity": "sha512-N39iBk0K71F9nb442TLbTkjl24FLUzuvx2i1I2RsEAQsdAdUTuUoW0vlfUXgkMTUOnYqKnWcFfqw4hK4Pw27hg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "fast-check": "^3.23.1" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/empathic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", + "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", + "license": "MIT" + }, + "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==", + "license": "MIT" + }, + "node_modules/exsolve": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", + "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/fast-check": { + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", + "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^6.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/fast-decode-uri-component": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", + "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==", + "license": "MIT" + }, + "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==", + "license": "MIT" + }, + "node_modules/fast-json-stringify": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-6.0.1.tgz", + "integrity": "sha512-s7SJE83QKBZwg54dIbD5rCtzOBVD43V1ReWXXYqBgwCwHLYAAT0RQc/FmrQglXqWPpz6omtryJQOau5jI4Nrvg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "@fastify/merge-json-schemas": "^0.2.0", + "ajv": "^8.12.0", + "ajv-formats": "^3.0.1", + "fast-uri": "^3.0.0", + "json-schema-ref-resolver": "^2.0.0", + "rfdc": "^1.2.0" + } + }, + "node_modules/fast-jwt": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/fast-jwt/-/fast-jwt-5.0.6.tgz", + "integrity": "sha512-LPE7OCGUl11q3ZgW681cEU2d0d2JZ37hhJAmetCgNyW8waVaJVZXhyFF6U2so1Iim58Yc7pfxJe2P7MNetQH2g==", + "license": "Apache-2.0", + "dependencies": { + "@lukeed/ms": "^2.0.2", + "asn1.js": "^5.4.1", + "ecdsa-sig-formatter": "^1.0.11", + "mnemonist": "^0.40.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/fast-querystring": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz", + "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==", + "license": "MIT", + "dependencies": { + "fast-decode-uri-component": "^1.0.1" + } + }, + "node_modules/fast-redact": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", + "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastfall": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/fastfall/-/fastfall-1.5.1.tgz", + "integrity": "sha512-KH6p+Z8AKPXnmA7+Iz2Lh8ARCMr+8WNPVludm1LGkZoD2MjY6LVnRMtTKhkdzI+jr0RzQWXKzKyBJm1zoHEL4Q==", + "license": "MIT", + "dependencies": { + "reusify": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fastify": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/fastify/-/fastify-5.6.1.tgz", + "integrity": "sha512-WjjlOciBF0K8pDUPZoGPhqhKrQJ02I8DKaDIfO51EL0kbSMwQFl85cRwhOvmSDWoukNOdTo27gLN549pLCcH7Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "@fastify/ajv-compiler": "^4.0.0", + "@fastify/error": "^4.0.0", + "@fastify/fast-json-stringify-compiler": "^5.0.0", + "@fastify/proxy-addr": "^5.0.0", + "abstract-logging": "^2.0.1", + "avvio": "^9.0.0", + "fast-json-stringify": "^6.0.0", + "find-my-way": "^9.0.0", + "light-my-request": "^6.0.0", + "pino": "^9.0.0", + "process-warning": "^5.0.0", + "rfdc": "^1.3.1", + "secure-json-parse": "^4.0.0", + "semver": "^7.6.0", + "toad-cache": "^3.7.0" + } + }, + "node_modules/fastify-plugin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-5.0.1.tgz", + "integrity": "sha512-HCxs+YnRaWzCl+cWRYFnHmeRFyR5GVnJTAaCJQiYzQSDwK9MgJdyAsuL3nh0EWRCYMgQ5MeziymvmAhUHYHDUQ==", + "license": "MIT" + }, + "node_modules/fastparallel": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/fastparallel/-/fastparallel-2.4.1.tgz", + "integrity": "sha512-qUmhxPgNHmvRjZKBFUNI0oZuuH9OlSIOXmJ98lhKPxMZZ7zS/Fi0wRHOihDSz0R1YiIOjxzOY4bq65YTcdBi2Q==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4", + "xtend": "^4.0.2" + } + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fastseries": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/fastseries/-/fastseries-1.7.2.tgz", + "integrity": "sha512-dTPFrPGS8SNSzAt7u/CbMKCJ3s01N04s4JFbORHcmyvVfVKmbhMD1VtRbh5enGHxkaQDqWyLefiKOGGmohGDDQ==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", + "license": "MIT" + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/file-stream-rotator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/file-stream-rotator/-/file-stream-rotator-0.6.1.tgz", + "integrity": "sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ==", + "license": "MIT", + "dependencies": { + "moment": "^2.29.1" + } + }, + "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, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-my-way": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-9.3.0.tgz", + "integrity": "sha512-eRoFWQw+Yv2tuYlK2pjFS2jGXSxSppAs3hSQjfxVKxM5amECzIgYYc1FEI8ZmhSh/Ig+FrKEz43NLRKJjYCZVg==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-querystring": "^1.0.0", + "safe-regex2": "^5.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", + "license": "MIT" + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "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, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/giget": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", + "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.0", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.6", + "nypm": "^0.6.0", + "pathe": "^2.0.3" + }, + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/glob": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz", + "integrity": "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.0.3", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "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, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/helmet": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.2.0.tgz", + "integrity": "sha512-ZRiwvN089JfMXokizgqEPXsl2Guk094yExfoDXR0cBYWxtBbaSww/w+vT4WEJsBW2iTUi1GgZ6swmoug3Oy4Xw==", + "license": "MIT", + "engines": { + "node": ">=16.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==", + "license": "MIT", + "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/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "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==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", + "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "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==", + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=0.12.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==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", + "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jiti": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.0.tgz", + "integrity": "sha512-VXe6RjJkBPj0ohtqaO8vSWP3ZhAKo66fKrFNCll4BTcwljPLz03pCbaNKfzGP5MbrCYcbJ7v0nOYYwUzTEIdXQ==", + "devOptional": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/json-schema-ref-resolver": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/json-schema-ref-resolver/-/json-schema-ref-resolver-2.0.1.tgz", + "integrity": "sha512-HG0SIB9X4J8bwbxCbnd5FfPEbcXAJYTi1pBJeP/QPON+w8ovSME8iRG+ElHNxZNX2Qh6eYn1GdzJFS4cDFfx0Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/json-schema-resolver": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-schema-resolver/-/json-schema-resolver-3.0.0.tgz", + "integrity": "sha512-HqMnbz0tz2DaEJ3ntsqtx3ezzZyDE7G56A/pPY/NGmrPu76UzsWquOpHFRAf5beTNXoH2LU5cQePVvRli1nchA==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fast-uri": "^3.0.5", + "rfdc": "^1.1.4" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/Eomm/json-schema-resolver?sponsor=1" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", + "license": "MIT" + }, + "node_modules/light-my-request": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-6.6.0.tgz", + "integrity": "sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause", + "dependencies": { + "cookie": "^1.0.1", + "process-warning": "^4.0.0", + "set-cookie-parser": "^2.6.0" + } + }, + "node_modules/light-my-request/node_modules/process-warning": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-4.0.1.tgz", + "integrity": "sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "license": "MIT", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/lru-cache": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", + "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "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==", + "license": "ISC" + }, + "node_modules/minimatch": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", + "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", + "license": "ISC", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "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==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mnemonist": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.40.0.tgz", + "integrity": "sha512-kdd8AFNig2AD5Rkih7EPCXhu/iMvwevQFX/uEiGhZyPZi7fHqOoF4V4kHLpCfysxXMgQ4B52kdPMCwARshKvEg==", + "license": "MIT", + "dependencies": { + "obliterator": "^2.0.4" + } + }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "license": "MIT", + "engines": { + "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==", + "license": "MIT" + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz", + "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nypm": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.2.tgz", + "integrity": "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.2", + "pathe": "^2.0.3", + "pkg-types": "^2.3.0", + "tinyexec": "^1.0.1" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": "^14.16.0 || >=16.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/obliterator": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.5.tgz", + "integrity": "sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==", + "license": "MIT" + }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "license": "MIT", + "dependencies": { + "fn.name": "1.x.x" + } + }, + "node_modules/openai": { + "version": "5.23.1", + "resolved": "https://registry.npmjs.org/openai/-/openai-5.23.1.tgz", + "integrity": "sha512-APxMtm5mln4jhKhAr0d5zP9lNsClx4QwJtg8RUvYSSyxYCTHLNJnLEcSHbJ6t0ori8Pbr9HZGfcPJ7LEy73rvQ==", + "license": "Apache-2.0", + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/openapi-types": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", + "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", + "license": "MIT" + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pino": { + "version": "9.11.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-9.11.0.tgz", + "integrity": "sha512-+YIodBB9sxcWeR8PrXC2K3gEDyfkUuVEITOcbqrfcj+z5QW4ioIcqZfYFbrLTYLsmAwunbS7nfU/dpBB6PZc1g==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^2.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^3.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz", + "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==", + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz", + "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==", + "license": "MIT" + }, + "node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, + "node_modules/prisma": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.16.2.tgz", + "integrity": "sha512-aRvldGE5UUJTtVmFiH3WfNFNiqFlAtePUxcI0UEGlnXCX7DqhiMT5TRYwncHFeA/Reca5W6ToXXyCMTeFPdSXA==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/config": "6.16.2", + "@prisma/engines": "6.16.2" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/process-warning": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", + "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" + }, + "node_modules/rc9": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", + "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "destr": "^2.0.3" + } + }, + "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==", + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ret": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.5.0.tgz", + "integrity": "sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "license": "MIT" + }, + "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" + } + ], + "license": "MIT" + }, + "node_modules/safe-regex2": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-5.0.0.tgz", + "integrity": "sha512-YwJwe5a51WlK7KbOJREPdjNrpViQBI3p4T50lfwPuDhZnE3XGVTlGvi+aolc5+RvxDD6bnUmjVsU9n1eboLUYw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "ret": "~0.5.0" + } + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/secure-json-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.0.0.tgz", + "integrity": "sha512-dxtLJO6sc35jWidmLxo7ij+Eg48PM/kleBsxpC8QJE0qJICe+KawkDQmvCMZUr9u7WKVHgMW6vy3fQ7zMiFZMA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", + "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sonic-boom": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.0.tgz", + "integrity": "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/steed": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/steed/-/steed-1.1.3.tgz", + "integrity": "sha512-EUkci0FAUiE4IvGTSKcDJIQ/eRUP2JJb56+fvZ4sdnguLTqIdKjSxUe138poW8mkvKWXW2sFPrgTsxqoISnmoA==", + "license": "MIT", + "dependencies": { + "fastfall": "^1.5.0", + "fastparallel": "^2.2.0", + "fastq": "^1.3.0", + "fastseries": "^1.7.0", + "reusify": "^1.0.0" + } + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "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/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "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==", + "license": "MIT" + }, + "node_modules/string-width-cjs/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==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "license": "MIT" + }, + "node_modules/thread-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz", + "integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==", + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + } + }, + "node_modules/tinyexec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", + "devOptional": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toad-cache": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.7.0.tgz", + "integrity": "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/typescript": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "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==", + "license": "MIT" + }, + "node_modules/uuid": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz", + "integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/winston": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", + "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", + "license": "MIT", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.7.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.9.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-daily-rotate-file": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/winston-daily-rotate-file/-/winston-daily-rotate-file-5.0.0.tgz", + "integrity": "sha512-JDjiXXkM5qvwY06733vf09I2wnMXpZEhxEVOSPenZMii+g7pcDcTBt2MRugnoi8BwVSuCT2jfRXBUy+n1Zz/Yw==", + "license": "MIT", + "dependencies": { + "file-stream-rotator": "^0.6.1", + "object-hash": "^3.0.0", + "triple-beam": "^1.4.1", + "winston-transport": "^4.7.0" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "winston": "^3" + } + }, + "node_modules/winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "license": "MIT", + "dependencies": { + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.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==", + "license": "MIT", + "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==", + "license": "MIT", + "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-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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==", + "license": "MIT", + "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/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==", + "license": "MIT" + }, + "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==", + "license": "MIT", + "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-cjs/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==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/yaml": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + } + } +} diff --git a/GPTutor-Backend-v2/package.json b/GPTutor-Backend-v2/package.json new file mode 100644 index 00000000..b7543060 --- /dev/null +++ b/GPTutor-Backend-v2/package.json @@ -0,0 +1,60 @@ +{ + "name": "gptutor-backend-v2", + "version": "1.0.0", + "description": "GPTutor Backend v2 - Fastify + SQLite + Prisma", + "main": "dist/index.js", + "scripts": { + "dev": "nodemon src/index.ts", + "build": "tsc", + "start": "node dist/index.js", + "test": "node test.js", + "test:rate-limits": "node scripts/test-rate-limits.js", + "test:rate-limit-middleware": "npx ts-node src/middleware/rateLimitMiddleware.test.ts", + "db:generate": "prisma generate", + "db:push": "prisma db push", + "db:migrate": "prisma migrate dev", + "db:studio": "prisma studio", + "docs": "node docs/serve.js", + "docs:open": "node docs/serve.js & start http://localhost:8080" + }, + "keywords": [ + "fastify", + "prisma", + "sqlite", + "typescript" + ], + "author": "", + "license": "ISC", + "dependencies": { + "@fastify/cors": "^10.0.1", + "@fastify/helmet": "^12.0.1", + "@fastify/jwt": "^9.0.1", + "@fastify/multipart": "^9.0.1", + "@fastify/rate-limit": "^10.1.1", + "@fastify/static": "^8.0.1", + "@fastify/swagger": "^9.1.0", + "@fastify/swagger-ui": "^5.0.1", + "@prisma/client": "^6.16.2", + "@types/uuid": "^10.0.0", + "@types/winston": "^2.4.4", + "aws-sdk": "^2.1691.0", + "compress-pdf": "^1.0.0", + "crypto-js": "^4.2.0", + "easy-yandex-s3": "^1.0.0", + "fastify": "^5.1.0", + "openai": "^5.23.1", + "sharp": "^0.33.5", + "uuid": "^13.0.0", + "winston": "^3.17.0", + "winston-daily-rotate-file": "^5.0.0" + }, + "devDependencies": { + "@types/crypto-js": "^4.2.2", + "@types/node": "^22.10.5", + "node-fetch": "^3.3.2", + "nodemon": "^3.1.9", + "prisma": "^6.16.2", + "ts-node": "^10.9.2", + "typescript": "^5.7.3" + } +} diff --git a/GPTutor-Backend-v2/prisma/dev.db b/GPTutor-Backend-v2/prisma/dev.db new file mode 100644 index 0000000000000000000000000000000000000000..f6fade24fca8f1d933823185b66496736813458c GIT binary patch literal 36864 zcmeI*PiWg#90zbI&i_C4SQ+kMqpD9aof7@G+%Zx&QByBY(mKwT9*QPQvLnZT6iaTJ z>`=0@!Po{H?9#(7yX>^F>n^(uRz_jx9mZg{K~IG-SPy%WO8|x6m^n3M#!VP4U&WY?hEov?>p{wc#@jh zaVO&cP{U&h>O?($_r%K+-%hNK|2>u%|E1SSD2D(9AOHafKmY;|fWR{rxWx|*B@zkx zqpWX~YIfPF*Mg@U$J)PvfUVs`OzHwD+~d2*-8?DEn|v5+Mf zkBIb6+Io4z-cB+XmkU~Meko94CXg+-I{Z zv)MT68{TG(e6P`sw%-h2>)}Z0eE2kSZEz^TCg|N* zSQm7_(+$^Iu(x&6!SMA^G|;O{xhtz0ah%iEqHgVLnhZJ;b#^k@36V^_GccG)CFu9} zMZdn0v-V;S9ud3S@L=SiG?_B{hY~#L_Sn9_L1%+^$6oM(BZBX5eDDI@nq=x~Y%p;) zLEqeW4ZChQwY>}UA8~=bmItGU#mUqM*XVFoefVlPt3u~+*B6D1W>r}BM6;@MfpGG5 z-=vXCXL3Y^A>;m5C8K6EOfpZ%tj<3^1Gp(JIx`yDgVQ^zbG)qSJJ(5+3(L!SExYu1 zAiveNqt;Jt>X8}Hchn3BRdqgmijmLL;oviMf;{N>ClvX^1_1~_00Izz00bZa0SG_< z0uX?}(--jQ(HV+5J>-oH44CzbShu$t>m1qqR(->@>H_`NgfR+$C2gDUxbX10|X!d0SG_<0uX=z1Rwwb2tWV=k-&KD^vK>a0-gW=-=X4n z-~#~&KmY;|fB*y_009U<00Izz!2e!AiFqT(SPL*%|9@cY4=OI7a3;PQ|DGITg8&2| z009U<00Izz00f>>f!)P{(V3Yu%e!yJ!d1m3U)g91WKnV6Zz-N4_*JVZuJ>FX%&8j{ zd%Eh{6?eVqH+6v%WR}aYf~@l#D=4faF_S`Ss_ItOec$!YO;1-`pZw@vi!HUy4cnjc z$T5jAwQU4H%V*Y_ZELDw`_rOYE|tZS%BozNgfT6fEy=varUli`D2l9#mKlVl2fw3l zfBD|OiOznv+E4O1d$XI5xV7m@KFKHTx2hG}txM}0Qln=+hU?ZG)9{^UW7@UK^Rv2J zGyLG!&-IE^F+AI7nd`dY=%mXH-_tpfll1GnpbPR9UT@i6yXH@k6Q3|y#mK0F%1bP7 zT4|E3!I5MQftAg)Y)L{%R0K5$EB|ngEX#i8vmZPA-CQgfy!nU8Hfyd+l9j_`6~k8A z=4Q`i4;eg(riZl`?#qXC*nv#g=$B!WtXhQt literal 0 HcmV?d00001 diff --git a/GPTutor-Backend-v2/prisma/schema.prisma b/GPTutor-Backend-v2/prisma/schema.prisma new file mode 100644 index 00000000..fc0cee20 --- /dev/null +++ b/GPTutor-Backend-v2/prisma/schema.prisma @@ -0,0 +1,45 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "sqlite" + url = env("DATABASE_URL") +} + +model User { + id String @id @default(cuid()) + email String? @unique + username String? @unique + vkId String? @unique + + balance Float @default(0.0) + apiKey String @unique + isActive Boolean @default(true) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + files File[] + + @@map("users") +} + +model File { + id String @id @default(cuid()) + userId String + type String + name String + url String + size Int + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@map("files") +} diff --git a/GPTutor-Backend-v2/scripts/test-rate-limits.js b/GPTutor-Backend-v2/scripts/test-rate-limits.js new file mode 100644 index 00000000..1cfe3e44 --- /dev/null +++ b/GPTutor-Backend-v2/scripts/test-rate-limits.js @@ -0,0 +1,136 @@ +#!/usr/bin/env node + +/** + * Скрипт для тестирования rate limiting + * Использование: node scripts/test-rate-limits.js [endpoint] [requests] + */ + +const http = require('http'); + +const ENDPOINTS = { + health: 'http://localhost:3001/health', + models: 'http://localhost:3001/v1/models', + // Добавьте другие эндпоинты по необходимости +}; + +const DEFAULT_REQUESTS = 10; +const DEFAULT_DELAY = 100; // миллисекунды между запросами + +function makeRequest(url) { + return new Promise((resolve, reject) => { + const startTime = Date.now(); + + const req = http.get(url, (res) => { + let data = ''; + + res.on('data', (chunk) => { + data += chunk; + }); + + res.on('end', () => { + const duration = Date.now() - startTime; + resolve({ + statusCode: res.statusCode, + headers: res.headers, + data: data, + duration: duration, + rateLimitRemaining: res.headers['x-ratelimit-remaining'], + rateLimitLimit: res.headers['x-ratelimit-limit'], + rateLimitReset: res.headers['x-ratelimit-reset'] + }); + }); + }); + + req.on('error', (err) => { + reject(err); + }); + + req.setTimeout(5000, () => { + req.destroy(); + reject(new Error('Request timeout')); + }); + }); +} + +async function testRateLimit(endpoint, numRequests = DEFAULT_REQUESTS, delay = DEFAULT_DELAY) { + console.log(`\n🧪 Тестирование rate limiting для ${endpoint}`); + console.log(`📊 Отправка ${numRequests} запросов с задержкой ${delay}ms между запросами\n`); + + const results = []; + const startTime = Date.now(); + + for (let i = 0; i < numRequests; i++) { + try { + const result = await makeRequest(endpoint); + results.push(result); + + const status = result.statusCode === 200 ? '✅' : + result.statusCode === 429 ? '🚫' : '❌'; + + console.log(`${status} Запрос ${i + 1}: ${result.statusCode} (${result.duration}ms)`); + + if (result.rateLimitRemaining !== undefined) { + console.log(` Rate Limit: ${result.rateLimitRemaining}/${result.rateLimitLimit} (reset: ${new Date(result.rateLimitReset * 1000).toLocaleTimeString()})`); + } + + if (result.statusCode === 429) { + console.log(` ⚠️ Rate limit exceeded! Response: ${result.data}`); + } + + } catch (error) { + console.log(`❌ Запрос ${i + 1}: Ошибка - ${error.message}`); + results.push({ error: error.message, statusCode: 0 }); + } + + if (i < numRequests - 1) { + await new Promise(resolve => setTimeout(resolve, delay)); + } + } + + const totalTime = Date.now() - startTime; + const successfulRequests = results.filter(r => r.statusCode === 200).length; + const rateLimitedRequests = results.filter(r => r.statusCode === 429).length; + const errorRequests = results.filter(r => r.statusCode === 0).length; + + console.log(`\n📈 Результаты тестирования:`); + console.log(` ✅ Успешных запросов: ${successfulRequests}`); + console.log(` 🚫 Rate limited: ${rateLimitedRequests}`); + console.log(` ❌ Ошибок: ${errorRequests}`); + console.log(` ⏱️ Общее время: ${totalTime}ms`); + console.log(` 📊 Среднее время запроса: ${Math.round(totalTime / numRequests)}ms`); + + if (rateLimitedRequests > 0) { + console.log(`\n🎯 Rate limiting работает! Заблокировано ${rateLimitedRequests} запросов.`); + } else { + console.log(`\n⚠️ Rate limiting не сработал. Возможно, лимиты слишком высокие или сервер не запущен.`); + } +} + +async function main() { + const args = process.argv.slice(2); + const endpointName = args[0] || 'health'; + const numRequests = parseInt(args[1]) || DEFAULT_REQUESTS; + const delay = parseInt(args[2]) || DEFAULT_DELAY; + + if (!ENDPOINTS[endpointName]) { + console.log(`❌ Неизвестный эндпоинт: ${endpointName}`); + console.log(`Доступные эндпоинты: ${Object.keys(ENDPOINTS).join(', ')}`); + process.exit(1); + } + + console.log('🚀 Запуск тестирования rate limiting...'); + console.log(`Сервер: ${ENDPOINTS[endpointName]}`); + + try { + await testRateLimit(ENDPOINTS[endpointName], numRequests, delay); + } catch (error) { + console.error('❌ Ошибка при тестировании:', error.message); + process.exit(1); + } +} + +if (require.main === module) { + main(); +} + +module.exports = { testRateLimit, makeRequest }; diff --git a/GPTutor-Backend-v2/src/config/rateLimitConfig.ts b/GPTutor-Backend-v2/src/config/rateLimitConfig.ts new file mode 100644 index 00000000..bcb6aaf5 --- /dev/null +++ b/GPTutor-Backend-v2/src/config/rateLimitConfig.ts @@ -0,0 +1,47 @@ +import { RateLimitOptions } from "../middleware/rateLimitMiddleware"; + +export const RATE_LIMIT_CONFIG: RateLimitOptions = { + "/health": { + max: 100, + timeWindow: 60 * 1000, + }, + + "/vk-test": { + max: 30, + timeWindow: 60 * 1000, + }, + + "/update-token": { + max: 5, + timeWindow: 60 * 1000, + }, + + "/upload": { + max: 10, + timeWindow: 60 * 1000, + }, + + "/v1/chat/completions": { + max: 500, + timeWindow: 60 * 1000, + }, + + "/v1/models": { + max: 50, + timeWindow: 60 * 1000, + }, +}; + +export function getRateLimitConfigForEnv(): RateLimitOptions { + return { ...RATE_LIMIT_CONFIG }; +} + +export function getRateLimitForRoute(route: string) { + const config = getRateLimitConfigForEnv(); + return ( + config[route] || { + max: 30, + timeWindow: 60 * 1000, + } + ); +} diff --git a/GPTutor-Backend-v2/src/controllers/AuthController.ts b/GPTutor-Backend-v2/src/controllers/AuthController.ts new file mode 100644 index 00000000..a31b767f --- /dev/null +++ b/GPTutor-Backend-v2/src/controllers/AuthController.ts @@ -0,0 +1,98 @@ +import { FastifyRequest, FastifyReply } from 'fastify'; +import { BaseController } from './BaseController'; +import { AuthService } from '../services/AuthService'; +import { createVkAuthMiddleware } from '../middleware/authMiddleware'; +import { RequestWithLogging } from '../middleware/loggingMiddleware'; +import { createRateLimitMiddleware, getRateLimitConfig } from '../middleware/rateLimitMiddleware'; + +interface AuthenticatedRequest extends RequestWithLogging { + vkUser: any; + dbUser: any; +} + +export class AuthController extends BaseController { + constructor( + fastify: any, + private authService: AuthService + ) { + super(fastify); + } + + registerRoutes(): void { + const vkAuthMiddleware = createVkAuthMiddleware(this.authService); + + const vkTestRateLimit = createRateLimitMiddleware(getRateLimitConfig('/vk-test')!); + + const updateTokenRateLimit = createRateLimitMiddleware(getRateLimitConfig('/update-token')!); + + this.fastify.get( + '/vk-test', + { + preHandler: [vkTestRateLimit, vkAuthMiddleware] as any + }, + this.vkTest.bind(this) + ); + + this.fastify.post( + '/update-token', + { + preHandler: [updateTokenRateLimit, vkAuthMiddleware] as any + }, + this.updateToken.bind(this) + ); + } + + private async vkTest(request: any, reply: FastifyReply) { + this.logInfo('VK test endpoint accessed', { + vkId: request.dbUser.vkId, + balance: request.dbUser.balance + }, request); + + return this.sendSuccess(reply, { + message: "VK authorization successful!", + vkData: request.vkUser, + dbUser: { + id: request.dbUser.id, + vkId: request.dbUser.vkId, + balance: request.dbUser.balance, + apiKey: request.dbUser.apiKey, + isActive: request.dbUser.isActive, + createdAt: request.dbUser.createdAt, + updatedAt: request.dbUser.updatedAt, + }, + timestamp: new Date().toISOString(), + }); + } + + private async updateToken(request: any, reply: FastifyReply) { + try { + this.logInfo('Token update requested', { + userId: request.dbUser.id, + vkId: request.dbUser.vkId + }, request); + + const updatedUser = await this.authService.updateUserToken(request.dbUser.id); + + this.logInfo('Token updated successfully', { + userId: updatedUser.id, + newApiKey: updatedUser.apiKey.substring(0, 10) + '...' + }, request); + + return this.sendSuccess(reply, { + message: "API token updated successfully!", + newApiKey: updatedUser.apiKey, + user: { + id: updatedUser.id, + vkId: updatedUser.vkId, + balance: updatedUser.balance, + isActive: updatedUser.isActive, + updatedAt: updatedUser.updatedAt, + }, + timestamp: new Date().toISOString(), + }); + } catch (error) { + this.logError('Token update failed', error, request); + return this.sendError(reply, 'Failed to update token', 500); + } + } +} diff --git a/GPTutor-Backend-v2/src/controllers/BaseController.ts b/GPTutor-Backend-v2/src/controllers/BaseController.ts new file mode 100644 index 00000000..21fb7332 --- /dev/null +++ b/GPTutor-Backend-v2/src/controllers/BaseController.ts @@ -0,0 +1,74 @@ +import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify'; +import { logger } from '../services/LoggerService'; +import { RequestWithLogging } from '../middleware/loggingMiddleware'; + +export abstract class BaseController { + constructor(protected fastify: FastifyInstance) {} + + abstract registerRoutes(): void; + + protected sendSuccess(reply: FastifyReply, data: any, statusCode = 200) { + return reply.code(statusCode).send(data); + } + + protected sendError(reply: FastifyReply, message: string, statusCode = 500, request?: RequestWithLogging) { + if (request) { + logger.warn(`Response error: ${message}`, { + requestId: request.requestId, + userId: request.userId, + statusCode, + url: request.url, + method: request.method + }); + } + return reply.code(statusCode).send({ error: message }); + } + + protected sendValidationError(reply: FastifyReply, message: string, request?: RequestWithLogging) { + return this.sendError(reply, message, 400, request); + } + + protected sendUnauthorized(reply: FastifyReply, message = 'Unauthorized', request?: RequestWithLogging) { + return this.sendError(reply, message, 401, request); + } + + protected sendNotFound(reply: FastifyReply, message = 'Not found', request?: RequestWithLogging) { + return this.sendError(reply, message, 404, request); + } + + protected sendInsufficientBalance(reply: FastifyReply, request?: RequestWithLogging) { + return this.sendError(reply, 'Insufficient balance', 402, request); + } + + protected logInfo(message: string, meta?: any, request?: RequestWithLogging) { + logger.info(message, { + ...meta, + requestId: request?.requestId, + userId: request?.userId + }); + } + + protected logError(message: string, error?: Error | any, meta?: any, request?: RequestWithLogging) { + logger.error(message, error, { + ...meta, + requestId: request?.requestId, + userId: request?.userId + }); + } + + protected logWarn(message: string, meta?: any, request?: RequestWithLogging) { + logger.warn(message, { + ...meta, + requestId: request?.requestId, + userId: request?.userId + }); + } + + protected logDebug(message: string, meta?: any, request?: RequestWithLogging) { + logger.debug(message, { + ...meta, + requestId: request?.requestId, + userId: request?.userId + }); + } +} diff --git a/GPTutor-Backend-v2/src/controllers/CompletionController.ts b/GPTutor-Backend-v2/src/controllers/CompletionController.ts new file mode 100644 index 00000000..c853fb82 --- /dev/null +++ b/GPTutor-Backend-v2/src/controllers/CompletionController.ts @@ -0,0 +1,353 @@ +import { FastifyRequest, FastifyReply } from "fastify"; +import { BaseController } from "./BaseController"; +import { UserRepository } from "../repositories/UserRepository"; +import { LLMCostEvaluate } from "../services/LLMCostEvaluate"; +import { OpenRouterService } from "../services/OpenRouterService"; +import { RequestWithLogging } from "../middleware/loggingMiddleware"; +import { logger } from "../services/LoggerService"; +import { authenticateUser } from "../utils/vkAuth"; +import { createRateLimitMiddleware, getRateLimitConfig } from "../middleware/rateLimitMiddleware"; + +interface CompletionRequest extends RequestWithLogging { + body: { + model?: string; + messages: Array<{ + role: "system" | "user" | "assistant"; + content: string; + }>; + max_tokens?: number; + temperature?: number; + top_p?: number; + frequency_penalty?: number; + presence_penalty?: number; + stop?: string[]; + stream?: boolean; + }; +} + +export class CompletionController extends BaseController { + constructor( + fastify: any, + private userRepository: UserRepository, + private llmCostService: LLMCostEvaluate, + private openRouterService: OpenRouterService, + private vkSecretKey: string = process.env.VK_SECRET_KEY || "" + ) { + super(fastify); + } + + registerRoutes(): void { + const completionsRateLimit = createRateLimitMiddleware(getRateLimitConfig('/v1/chat/completions')!); + + this.fastify.post( + "/v1/chat/completions", + { preHandler: completionsRateLimit }, + this.chatCompletions.bind(this) + ); + } + + private async chatCompletions(request: any, reply: FastifyReply) { + try { + const authHeader = request.headers.authorization; + + const authResult = await authenticateUser( + authHeader, + this.vkSecretKey, + this.userRepository + ); + + if (!authResult) { + return this.sendUnauthorized( + reply, + "Invalid authentication. Use Bearer token (sk-...) or VK authorization.", + request + ); + } + + let user; + let userId; + + if (authResult.authType === "api_key") { + user = authResult.user; + userId = user.id.toString(); + } else if (authResult.authType === "vk") { + const vkData = authResult.user; + let dbUser = await this.userRepository.findByVkId(vkData.vk_user_id); + + if (!dbUser) { + dbUser = await this.userRepository.create({ + vkId: vkData.vk_user_id, + balance: 0.0, + isActive: true, + }); + } + + user = dbUser; + userId = user.id.toString(); + } else { + return this.sendUnauthorized( + reply, + "Unknown authentication type", + request + ); + } + + if (!user.isActive) { + return this.sendUnauthorized( + reply, + "User account is inactive", + request + ); + } + + request.userId = userId; + + const requestBody = request.body; + if (!requestBody.messages || !Array.isArray(requestBody.messages)) { + return this.sendValidationError( + reply, + "messages array is required", + request + ); + } + + const model = requestBody.model || "google/gemini-2.5-flash-lite"; + + this.logInfo( + `LLM request initiated`, + { + model, + messagesCount: requestBody.messages.length, + stream: requestBody.stream || false, + }, + request + ); + + const openRouterParams = { + model, + messages: requestBody.messages, + max_tokens: requestBody.max_tokens, + temperature: requestBody.temperature, + top_p: requestBody.top_p, + frequency_penalty: requestBody.frequency_penalty, + presence_penalty: requestBody.presence_penalty, + stop: requestBody.stop, + }; + + if (requestBody.stream) { + return this.handleStreamingResponse( + reply, + user, + model, + openRouterParams, + request + ); + } + + return this.handleNonStreamingResponse( + reply, + user, + openRouterParams, + request + ); + } catch (error) { + this.logError("Completion API error", error, {}, request); + + if (error instanceof Error) { + if (error.message === "User not found") { + return this.sendUnauthorized(reply, "Invalid API key", request); + } + if (error.message === "Insufficient balance") { + return this.sendInsufficientBalance(reply, request); + } + } + + return this.sendError(reply, "Internal server error", 500, request); + } + } + + private async handleStreamingResponse( + reply: FastifyReply, + user: any, + model: string, + openRouterParams: any, + request: CompletionRequest + ) { + reply.raw.setHeader("Cache-Control", "no-cache"); + reply.raw.setHeader("Connection", "keep-alive"); + reply.raw.setHeader("X-Accel-Buffering", "no"); + reply.raw.setHeader("Access-Control-Allow-Origin", "*"); + reply.raw.setHeader("Content-type", "text/event-stream"); + + let totalCost = 0; + + try { + logger.llmRequest(model, user.id.toString(), undefined, undefined, { + requestId: request.requestId, + stream: true, + }); + + const streamStartTime = Date.now(); + + const stream = await this.openRouterService.createCompletionStream({ + ...openRouterParams, + stream: true, + }); + + let chunkCount = 0; + + for await (const chunk of stream) { + chunkCount++; + + if (chunk.usage) { + totalCost = this.llmCostService.calculateCost( + (chunk.usage as any)?.cost_details + ?.upstream_inference_completions_cost || 0 + ); + + chunk.usage = { + ...chunk.usage, + cost_details: { upstream_inference_completions_cost: totalCost }, + } as any; + } + + const chunkData = `data: ${JSON.stringify(chunk)}\n\n`; + reply.raw.write(chunkData); + + if (chunkCount % 50 === 0) { + this.logDebug( + `Streaming progress: ${chunkCount} chunks sent`, + {}, + request + ); + } + } + + reply.raw.write("data: [DONE]\n\n"); + + reply.raw.end(); + + const streamDuration = Date.now() - streamStartTime; + + logger.llmResponse( + model, + user.id.toString(), + 0, + totalCost, + streamDuration, + { + requestId: request.requestId, + chunks: chunkCount, + stream: true, + } + ); + + await this.userRepository.decreaseBalance(user.id, totalCost); + + return; + } catch (streamError) { + this.logError("Stream error", streamError, { model }, request); + + try { + reply.raw.write( + `data: ${JSON.stringify({ + error: "Stream error", + message: + streamError instanceof Error + ? streamError.message + : "Unknown error", + })}\n\n` + ); + reply.raw.write("data: [DONE]\n\n"); + reply.raw.end(); + } catch (writeError) { + this.logError( + "Error writing error response to stream", + writeError, + {}, + request + ); + } + + return; + } + } + + private async handleNonStreamingResponse( + reply: FastifyReply, + user: any, + openRouterParams: any, + request: CompletionRequest + ) { + const requestStartTime = Date.now(); + + logger.llmRequest( + openRouterParams.model, + user.id.toString(), + undefined, + undefined, + { + requestId: request.requestId, + stream: false, + } + ); + + const completion = await this.openRouterService.createCompletion({ + ...openRouterParams, + stream: false, + }); + + const originalCostUsd = (completion.usage as any)?.cost_details + ?.upstream_inference_completions_cost; + const cost = this.llmCostService.calculateCost(originalCostUsd); + const requestDuration = Date.now() - requestStartTime; + const totalTokens = (completion.usage as any)?.total_tokens || 0; + + await this.userRepository.decreaseBalance(user.id, cost); + + // Get updated user by ID instead of API key (since VK auth doesn't have API key) + const updatedUser = + (await this.userRepository.findByVkId(user.vkId || "")) || + (await this.userRepository.findByApiKey( + request.headers.authorization?.substring(7) || "" + )); + + logger.llmResponse( + openRouterParams.model, + user.id.toString(), + totalTokens, + cost, + requestDuration, + { + requestId: request.requestId, + originalCostUsd, + remainingBalance: updatedUser?.balance, + } + ); + + logger.balance( + "decrease", + user.id.toString(), + cost, + updatedUser?.balance || 0, + { + requestId: request.requestId, + reason: "llm_completion", + } + ); + + console.log({ + ...completion.usage, + cost_details: { upstream_inference_completions_cost: cost }, + }); + const responseWithCost = { + ...completion, + usage: { + ...completion.usage, + cost_details: { upstream_inference_completions_cost: cost }, + }, + }; + + return this.sendSuccess(reply, responseWithCost); + } +} diff --git a/GPTutor-Backend-v2/src/controllers/FilesController.ts b/GPTutor-Backend-v2/src/controllers/FilesController.ts new file mode 100644 index 00000000..9162986a --- /dev/null +++ b/GPTutor-Backend-v2/src/controllers/FilesController.ts @@ -0,0 +1,129 @@ +import { FastifyRequest, FastifyReply } from "fastify"; +import { BaseController } from "./BaseController"; +import { FilesService } from "../services/FilesService"; +import { FileRepository } from "../repositories/FileRepository"; +import { RequestWithLogging } from "../middleware/loggingMiddleware"; +import { createVkAuthMiddleware } from "../middleware/authMiddleware"; +import { AuthService } from "../services/AuthService"; +import { + createRateLimitMiddleware, + getRateLimitConfig, +} from "../middleware/rateLimitMiddleware"; + +interface FileUploadRequest extends RequestWithLogging { + vkUser: any; + dbUser: any; +} + +export class FilesController extends BaseController { + constructor( + fastify: any, + private filesService: FilesService, + private fileRepository: FileRepository, + private authService: AuthService + ) { + super(fastify); + } + + registerRoutes(): void { + const vkAuthMiddleware = createVkAuthMiddleware(this.authService); + + const uploadRateLimit = createRateLimitMiddleware( + getRateLimitConfig("/upload")! + ); + + this.fastify.post( + "/upload", + { + preHandler: [uploadRateLimit, vkAuthMiddleware] as any, + config: { + bodyLimit: 50 * 1024 * 1024, + }, + }, + this.uploadFile.bind(this) + ); + } + + private async uploadFile(request: any, reply: FastifyReply) { + try { + this.logInfo("File upload requested", { + userId: request.dbUser.id, + vkId: request.dbUser.vkId, + }); + + const data = await (request as any).file(); + + if (!data) { + return this.sendError(reply, "No file provided", 400, request); + } + + const maxSize = 50 * 1024 * 1024; + if (data.file.bytesRead > maxSize) { + return this.sendError( + reply, + "File too large. Maximum size is 50MB", + 413, + request + ); + } + + const fileBuffer = await data.toBuffer(); + const arrayBuffer = fileBuffer.buffer.slice( + fileBuffer.byteOffset, + fileBuffer.byteOffset + fileBuffer.byteLength + ); + + this.logInfo("Processing file", { + fileName: data.filename, + fileSize: data.file.bytesRead, + mimeType: data.mimetype, + }); + + const result = await this.filesService.optimizeAndUploadFile( + arrayBuffer, + data.filename + ); + + const savedFile = await this.fileRepository.create({ + userId: request.dbUser.id, + type: data.mimetype, + name: data.filename, + url: result.url, + size: data.file.bytesRead, + }); + + this.logInfo("File uploaded successfully", { + fileId: savedFile.id, + fileName: savedFile.name, + url: savedFile.url, + userId: request.dbUser.id, + }); + + return this.sendSuccess(reply, { + message: "File uploaded successfully!", + file: { + id: savedFile.id, + name: savedFile.name, + type: savedFile.type, + url: savedFile.url, + size: savedFile.size, + createdAt: savedFile.createdAt, + }, + timestamp: new Date().toISOString(), + }); + } catch (error) { + this.logError("File upload failed", error); + + if (error instanceof Error) { + if (error.message.includes("Unknown or unsupported file type")) { + return this.sendError(reply, "Unsupported file type", 400, request); + } + if (error.message.includes("Invalid filename")) { + return this.sendError(reply, "Invalid filename", 400, request); + } + } + + return this.sendError(reply, "Failed to upload file", 500, request); + } + } +} diff --git a/GPTutor-Backend-v2/src/controllers/HealthController.ts b/GPTutor-Backend-v2/src/controllers/HealthController.ts new file mode 100644 index 00000000..7ebec861 --- /dev/null +++ b/GPTutor-Backend-v2/src/controllers/HealthController.ts @@ -0,0 +1,22 @@ +import { FastifyRequest, FastifyReply } from 'fastify'; +import { BaseController } from './BaseController'; +import { createRateLimitMiddleware, getRateLimitConfig } from '../middleware/rateLimitMiddleware'; + +export class HealthController extends BaseController { + registerRoutes(): void { + const healthRateLimit = createRateLimitMiddleware(getRateLimitConfig('/health')!); + + this.fastify.get( + '/health', + { preHandler: healthRateLimit }, + this.healthCheck.bind(this) + ); + } + + private async healthCheck(request: FastifyRequest, reply: FastifyReply) { + return this.sendSuccess(reply, { + status: "ok", + timestamp: new Date().toISOString() + }); + } +} diff --git a/GPTutor-Backend-v2/src/controllers/ModelsController.ts b/GPTutor-Backend-v2/src/controllers/ModelsController.ts new file mode 100644 index 00000000..a1322711 --- /dev/null +++ b/GPTutor-Backend-v2/src/controllers/ModelsController.ts @@ -0,0 +1,148 @@ +import { FastifyRequest, FastifyReply } from "fastify"; +import { BaseController } from "./BaseController"; +import { LLMCostEvaluate } from "../services/LLMCostEvaluate"; +import { RequestWithLogging } from "../middleware/loggingMiddleware"; +import { createRateLimitMiddleware, getRateLimitConfig } from "../middleware/rateLimitMiddleware"; + +export class ModelsController extends BaseController { + constructor(protected fastify: any, private llmCostService: LLMCostEvaluate) { + super(fastify); + } + + registerRoutes(): void { + // Rate limiting для models endpoint + const modelsRateLimit = createRateLimitMiddleware(getRateLimitConfig('/v1/models')!); + + this.fastify.get( + "/v1/models", + { preHandler: modelsRateLimit }, + this.getModels.bind(this) + ); + } + + private async getModels(request: FastifyRequest, reply: FastifyReply) { + try { + this.logInfo( + "Getting popular provider models", + {}, + request as RequestWithLogging + ); + + // Проверяем, что сервис инициализирован + const allModels = this.llmCostService.getAllModels(); + if (!allModels || allModels.length === 0) { + this.logWarn( + "LLM Cost Service not initialized or no models loaded", + {}, + request as RequestWithLogging + ); + return this.sendError( + reply, + "Models service not ready", + 503, + request as RequestWithLogging + ); + } + + const models = this.llmCostService.getPopularProviderModels(); + + // Проверяем, что модели загружены корректно + if (!models || models.length === 0) { + this.logWarn( + "No models found from popular providers", + {}, + request as RequestWithLogging + ); + return this.sendSuccess(reply, { + success: true, + data: { + models: [], + total: 0, + providers: [ + "x-ai", + "deepseek", + "google", + "qwen", + "perplexity", + "mistralai", + "openai", + ], + lastUpdated: new Date().toISOString(), + }, + }); + } + + // Логируем информацию о моделях для отладки + this.logInfo( + `Found ${models.length} models from popular providers`, + { + modelCount: models.length, + sampleModel: models[0] + ? { + id: models[0].id, + hasPricingRub: !!models[0].pricing_rub, + hasPrompt: !!models[0].pricing_rub?.prompt, + } + : null, + }, + request as RequestWithLogging + ); + + const sortedModels = models.sort((a, b) => { + // Безопасное получение цены с проверкой на существование + const priceA = a.pricing_rub?.prompt || 0; + const priceB = b.pricing_rub?.prompt || 0; + + // Сначала сравниваем по цене (самые дорогие сверху) + const priceDiff = priceB - priceA; + if (priceDiff !== 0) { + return priceDiff; + } + + // Если цены равны, сравниваем по дате создания (самые новые сверху) + const createdA = a.created || 0; + const createdB = b.created || 0; + return createdB - createdA; + }); + + this.logInfo( + `Retrieved ${sortedModels.length} popular models (sorted by price and creation date)`, + { + modelCount: sortedModels.length, + }, + request as RequestWithLogging + ); + + return this.sendSuccess(reply, { + success: true, + data: { + models: sortedModels, + total: sortedModels.length, + providers: [ + "x-ai", + "deepseek", + "google", + "qwen", + "perplexity", + "mistralai", + "openai", + ], + lastUpdated: new Date().toISOString(), + }, + }); + } catch (error) { + this.logError( + "Failed to get models", + error, + {}, + request as RequestWithLogging + ); + return this.sendError( + reply, + "Failed to retrieve models", + 500, + request as RequestWithLogging + ); + } + } +} diff --git a/GPTutor-Backend-v2/src/controllers/index.ts b/GPTutor-Backend-v2/src/controllers/index.ts new file mode 100644 index 00000000..71a5927f --- /dev/null +++ b/GPTutor-Backend-v2/src/controllers/index.ts @@ -0,0 +1,54 @@ +import { FastifyInstance } from 'fastify'; +import { HealthController } from './HealthController'; +import { AuthController } from './AuthController'; +import { CompletionController } from './CompletionController'; +import { ModelsController } from './ModelsController'; +import { FilesController } from './FilesController'; +import { AuthService } from '../services/AuthService'; +import { UserRepository } from '../repositories/UserRepository'; +import { FileRepository } from '../repositories/FileRepository'; +import { LLMCostEvaluate } from '../services/LLMCostEvaluate'; +import { OpenRouterService } from '../services/OpenRouterService'; +import { FilesService } from '../services/FilesService'; + +export function registerControllers( + fastify: FastifyInstance, + dependencies: { + authService: AuthService; + userRepository: UserRepository; + fileRepository: FileRepository; + filesService: FilesService; + llmCostService: LLMCostEvaluate; + openRouterService: OpenRouterService; + } +) { + const controllers = [ + new HealthController(fastify), + new AuthController(fastify, dependencies.authService), + new CompletionController( + fastify, + dependencies.userRepository, + dependencies.llmCostService, + dependencies.openRouterService + ), + new ModelsController( + fastify, + dependencies.llmCostService + ), + new FilesController( + fastify, + dependencies.filesService, + dependencies.fileRepository, + dependencies.authService + ), + ]; + + controllers.forEach(controller => controller.registerRoutes()); +} + +export * from './BaseController'; +export * from './HealthController'; +export * from './AuthController'; +export * from './CompletionController'; +export * from './ModelsController'; +export * from './FilesController'; diff --git a/GPTutor-Backend-v2/src/index.ts b/GPTutor-Backend-v2/src/index.ts new file mode 100644 index 00000000..702e55e1 --- /dev/null +++ b/GPTutor-Backend-v2/src/index.ts @@ -0,0 +1,189 @@ +import Fastify from "fastify"; +import { PrismaClient } from "@prisma/client"; +import { UserRepository } from "./repositories/UserRepository"; +import { FileRepository } from "./repositories/FileRepository"; +import { AuthService } from "./services/AuthService"; +import { FilesService } from "./services/FilesService"; +import { LLMCostEvaluate } from "./services/LLMCostEvaluate"; +import { OpenRouterService } from "./services/OpenRouterService"; +import { logger } from "./services/LoggerService"; +import { registerControllers } from "./controllers"; +import { + createLoggingMiddleware, + createErrorLoggingMiddleware, +} from "./middleware/loggingMiddleware"; +import { createRateLimitMiddleware, getRateLimitConfig, cleanupRateLimitStore } from "./middleware/rateLimitMiddleware"; + +const prisma = new PrismaClient(); +const userRepository = new UserRepository(prisma); +const fileRepository = new FileRepository(prisma); + +// VK App credentials +const VK_APP_ID = "51602327"; +const VK_SECRET_KEY = "7JnZrfRn0LOp9mN1CHIF"; + +// OpenRouter credentials +const OPENROUTER_API_KEY = + "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"; + +const authService = new AuthService(userRepository, VK_APP_ID, VK_SECRET_KEY); +const filesService = new FilesService(); +const llmCostService = new LLMCostEvaluate(90); // 90 рублей за доллар +const openRouterService = new OpenRouterService(OPENROUTER_API_KEY); + +const fastify = Fastify({ + logger: true, + disableRequestLogging: true, +}); + +fastify.register(require("@fastify/cors"), { + origin: "*", + methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], + allowedHeaders: [ + "Content-Type", + "Authorization", + "Accept", + "Cache-Control", + "Pragma", + ], + credentials: true, + optionsSuccessStatus: 200, +}); + +fastify.register(require("@fastify/helmet")); + +// Register rate limiting +fastify.register(require("@fastify/rate-limit"), { + max: 100, // дефолтный лимит + timeWindow: 60 * 1000, // 1 минута + keyGenerator: (request: any) => { + const ip = request.ip; + const userId = request.userId || 'anonymous'; + return `rate_limit:${ip}:${userId}`; + }, + errorResponseBuilder: (request: any, context: any) => { + return { + error: 'Too Many Requests', + message: `Rate limit exceeded. Maximum ${context.max} requests per ${context.timeWindow / 1000} seconds.`, + retryAfter: Math.ceil(context.after / 1000) + }; + } +}); + +// Register multipart support for file uploads +fastify.register(require("@fastify/multipart"), { + limits: { + fileSize: 50 * 1024 * 1024, // 50MB limit + }, +}); + +// Register simple logging +fastify.addHook("preHandler", async (request: any, reply) => { + request.requestId = require("uuid").v4(); + request.startTime = Date.now(); + logger.apiRequest(request.method, request.url, request.userId, { + requestId: request.requestId, + userAgent: request.headers["user-agent"], + ip: request.ip, + }); +}); + +fastify.addHook("onResponse", async (request: any, reply) => { + const duration = Date.now() - (request.startTime || 0); + logger.apiResponse( + request.method, + request.url, + reply.statusCode, + duration, + request.userId, + { + requestId: request.requestId, + } + ); +}); + +fastify.setErrorHandler(async (error, request: any, reply) => { + const duration = Date.now() - (request.startTime || 0); + logger.error(`Request failed: ${request.method} ${request.url}`, error, { + requestId: request.requestId, + userId: request.userId, + duration, + statusCode: reply.statusCode, + }); + throw error; +}); + +// Register all controllers +registerControllers(fastify, { + authService, + userRepository, + fileRepository, + filesService, + llmCostService, + openRouterService, +}); + +// Rate limiting уже настроен в middleware с автоматической очисткой + +const start = async () => { + try { + logger.info("Starting GPTutor Backend v2..."); + + await llmCostService.initialize(); + logger.info("LLM Cost Service initialized", { + totalModels: llmCostService.getStats().totalModels, + }); + + await fastify.listen({ + port: Number(process.env.PORT) || 3001, + host: "0.0.0.0", + }); + + logger.info("🚀 Server is running", { + port: Number(process.env.PORT) || 3001, + host: "0.0.0.0", + environment: process.env.NODE_ENV || "development", + }); + } catch (err) { + logger.error("Failed to start server", err); + process.exit(1); + } +}; + +process.on("SIGINT", async () => { + logger.info("Received SIGINT, shutting down gracefully..."); + try { + await fastify.close(); + await prisma.$disconnect(); + logger.info("Server shut down successfully"); + process.exit(0); + } catch (error) { + logger.error("Error during shutdown", error); + process.exit(1); + } +}); + +process.on("SIGTERM", async () => { + logger.info("Received SIGTERM, shutting down gracefully..."); + try { + await fastify.close(); + await prisma.$disconnect(); + logger.info("Server shut down successfully"); + process.exit(0); + } catch (error) { + logger.error("Error during shutdown", error); + process.exit(1); + } +}); + +process.on("uncaughtException", (error) => { + logger.error("Uncaught Exception", error); + process.exit(1); +}); + +process.on("unhandledRejection", (reason, promise) => { + logger.error("Unhandled Rejection", reason, { promise }); + process.exit(1); +}); + +start(); diff --git a/GPTutor-Backend-v2/src/middleware/authMiddleware.ts b/GPTutor-Backend-v2/src/middleware/authMiddleware.ts new file mode 100644 index 00000000..1f0d492e --- /dev/null +++ b/GPTutor-Backend-v2/src/middleware/authMiddleware.ts @@ -0,0 +1,41 @@ +import { FastifyRequest, FastifyReply } from 'fastify'; +import { AuthService } from '../services/AuthService'; +import { RequestWithLogging } from './loggingMiddleware'; +import { logger } from '../services/LoggerService'; + +export function createVkAuthMiddleware(authService: AuthService) { + return async function vkAuthMiddleware(request: RequestWithLogging, reply: FastifyReply) { + const authHeader = request.headers.authorization; + + if (!authHeader || !authHeader.startsWith("Bearer ")) { + reply.code(401).send({ error: "Missing or invalid authorization header" }); + return; + } + + const token = authHeader.substring(7); // Remove "Bearer " + + try { + const authResult = await authService.authorizeVKUser(token); + (request as any).vkUser = authResult.vkData; + (request as any).dbUser = authResult.dbUser; + + // Set userId for logging + request.userId = authResult.dbUser.id.toString(); + + logger.auth('vk_authorize', request.userId, true, { + requestId: request.requestId, + vkId: (authResult.vkData as any).id + }); + } catch (error) { + logger.auth('vk_authorize', request.userId, false, { + requestId: request.requestId, + error: error instanceof Error ? error.message : 'Unknown error' + }); + + reply.code(401).send({ + error: error instanceof Error ? error.message : "Authorization failed", + }); + return; + } + }; +} diff --git a/GPTutor-Backend-v2/src/middleware/loggingMiddleware.ts b/GPTutor-Backend-v2/src/middleware/loggingMiddleware.ts new file mode 100644 index 00000000..74f59430 --- /dev/null +++ b/GPTutor-Backend-v2/src/middleware/loggingMiddleware.ts @@ -0,0 +1,64 @@ +import { FastifyRequest, FastifyReply } from 'fastify'; +import { logger } from '../services/LoggerService'; +import { v4 as uuidv4 } from 'uuid'; + +export interface RequestWithLogging extends FastifyRequest { + requestId: string; + startTime: number; + userId?: string; +} + +export function createLoggingMiddleware() { + return async function loggingMiddleware(request: RequestWithLogging, reply: FastifyReply) { + // Generate unique request ID + request.requestId = uuidv4(); + request.startTime = Date.now(); + + // Try to extract user ID from various sources + const authHeader = request.headers.authorization; + if (authHeader && authHeader.startsWith('Bearer ')) { + // This will be set by auth middleware later, but we can try to extract it + request.userId = 'unknown'; // Will be updated by auth middleware + } + + // Log incoming request + logger.apiRequest( + request.method, + request.url, + request.userId, + { + requestId: request.requestId, + userAgent: request.headers['user-agent'], + ip: request.ip, + headers: { + 'content-type': request.headers['content-type'], + 'authorization': authHeader ? 'Bearer [REDACTED]' : undefined + } + } + ); + + // We'll log response in the main request handler instead + // since Fastify's hook system has complex typing + + // Add request ID to response headers for tracking + reply.header('X-Request-ID', request.requestId); + }; +} + +export function createErrorLoggingMiddleware() { + return async function errorLoggingMiddleware(error: Error, request: RequestWithLogging, reply: FastifyReply) { + const duration = Date.now() - request.startTime; + + logger.error(`Request failed: ${request.method} ${request.url}`, error, { + requestId: request.requestId, + userId: request.userId, + duration, + statusCode: reply.statusCode, + userAgent: request.headers['user-agent'], + ip: request.ip + }); + + // Don't modify the error, just log it + throw error; + }; +} diff --git a/GPTutor-Backend-v2/src/middleware/rateLimitMiddleware.test.ts b/GPTutor-Backend-v2/src/middleware/rateLimitMiddleware.test.ts new file mode 100644 index 00000000..40813f80 --- /dev/null +++ b/GPTutor-Backend-v2/src/middleware/rateLimitMiddleware.test.ts @@ -0,0 +1,76 @@ +import { createRateLimitMiddleware, cleanupRateLimitStore, getGlobalRateLimitStore } from './rateLimitMiddleware'; + +// Простой тест для проверки работы rate limiting +async function testRateLimitMiddleware() { + console.log('🧪 Тестирование rate limiting middleware...'); + + const config = { + max: 3, + timeWindow: 1000, // 1 секунда для быстрого тестирования + }; + + const middleware = createRateLimitMiddleware(config); + + // Создаем мок объекты + const mockRequest = { + ip: '127.0.0.1', + url: '/test', + method: 'GET', + headers: { 'user-agent': 'test-agent' } + } as any; + + const mockReply = { + code: (status: number) => ({ + send: (data: any) => { + console.log(`Response ${status}:`, data); + return { status, data }; + } + }), + header: (name: string, value: string) => { + console.log(`Header ${name}: ${value}`); + } + } as any; + + console.log('\n📊 Тестирование нормальных запросов...'); + + // Тест 1-3: нормальные запросы + for (let i = 1; i <= 3; i++) { + console.log(`Запрос ${i}:`); + await middleware(mockRequest, mockReply); + } + + console.log('\n🚫 Тестирование превышения лимита...'); + + // Тест 4: превышение лимита + console.log('Запрос 4 (должен быть заблокирован):'); + await middleware(mockRequest, mockReply); + + console.log('\n🧹 Тестирование очистки store...'); + + // Проверяем размер store до очистки + const store = getGlobalRateLimitStore(); + console.log(`Store size before cleanup: ${store.size}`); + + // Ждем истечения времени окна + console.log('Ожидание истечения timeWindow...'); + await new Promise(resolve => setTimeout(resolve, 1100)); + + // Очищаем store + cleanupRateLimitStore(store); + console.log(`Store size after cleanup: ${store.size}`); + + console.log('\n✅ Тест после очистки...'); + + // Тест после очистки - должен работать снова + console.log('Запрос после очистки:'); + await middleware(mockRequest, mockReply); + + console.log('\n🎉 Тестирование завершено!'); +} + +// Запуск теста, если файл выполняется напрямую +if (require.main === module) { + testRateLimitMiddleware().catch(console.error); +} + +export { testRateLimitMiddleware }; diff --git a/GPTutor-Backend-v2/src/middleware/rateLimitMiddleware.ts b/GPTutor-Backend-v2/src/middleware/rateLimitMiddleware.ts new file mode 100644 index 00000000..e7d4cc50 --- /dev/null +++ b/GPTutor-Backend-v2/src/middleware/rateLimitMiddleware.ts @@ -0,0 +1,127 @@ +import { FastifyRequest, FastifyReply } from "fastify"; +import { logger } from "../services/LoggerService"; +import { getRateLimitForRoute } from "../config/rateLimitConfig"; + +export interface RateLimitConfig { + max: number; + timeWindow: number; + keyGenerator?: (request: FastifyRequest) => string; + onLimitReached?: (request: FastifyRequest, reply: FastifyReply) => void; + skipSuccessfulRequests?: boolean; + skipFailedRequests?: boolean; +} + +export interface RateLimitOptions { + [route: string]: RateLimitConfig; +} + +export function generateRateLimitKey(request: FastifyRequest): string { + const ip = request.ip; + const userId = (request as any).userId || "anonymous"; + const userAgent = request.headers["user-agent"] || "unknown"; + + return `rate_limit:${ip}:${userId}:${Buffer.from(userAgent) + .toString("base64") + .slice(0, 10)}`; +} + +export function generateIPRateLimitKey(request: FastifyRequest): string { + const ip = request.ip; + return `rate_limit:${ip}`; +} + +const globalRateLimitStore = new Map< + string, + { count: number; resetTime: number } +>(); + +export function createRateLimitMiddleware(config: RateLimitConfig) { + const store = globalRateLimitStore; + + return async (request: FastifyRequest, reply: FastifyReply) => { + const key = config.keyGenerator + ? config.keyGenerator(request) + : generateIPRateLimitKey(request); + const now = Date.now(); + + let record = store.get(key); + + if (!record || now > record.resetTime) { + record = { + count: 0, + resetTime: now + config.timeWindow, + }; + store.set(key, record); + } + + record.count++; + + if (record.count > config.max) { + logger.warn("Rate limit exceeded", { + ip: request.ip, + url: request.url, + method: request.method, + key, + count: record.count, + max: config.max, + timeWindow: config.timeWindow, + }); + + if (config.onLimitReached) { + config.onLimitReached(request, reply); + } else { + reply.code(429).send({ + error: "Too Many Requests", + message: `Rate limit exceeded. Maximum ${config.max} requests per ${ + config.timeWindow / 1000 + } seconds.`, + retryAfter: Math.ceil((record.resetTime - now) / 1000), + }); + } + return; + } + + reply.header("X-RateLimit-Limit", config.max.toString()); + reply.header( + "X-RateLimit-Remaining", + Math.max(0, config.max - record.count).toString() + ); + reply.header( + "X-RateLimit-Reset", + Math.ceil(record.resetTime / 1000).toString() + ); + + store.set(key, record); + }; +} + +export function getRateLimitConfig(route: string): RateLimitConfig | null { + const env = process.env.NODE_ENV || "production"; + return getRateLimitForRoute(route); +} + +export function cleanupRateLimitStore( + store: Map +) { + const now = Date.now(); + let cleanedCount = 0; + + for (const [key, record] of store.entries()) { + if (now > record.resetTime) { + store.delete(key); + cleanedCount++; + } + } + + if (cleanedCount > 0) { + logger.debug(`Cleaned up ${cleanedCount} expired rate limit records`); + } +} + +export function getGlobalRateLimitStore() { + return globalRateLimitStore; +} + +setInterval(() => { + cleanupRateLimitStore(globalRateLimitStore); +}, 5 * 60 * 1000); diff --git a/GPTutor-Backend-v2/src/repositories/FileRepository.ts b/GPTutor-Backend-v2/src/repositories/FileRepository.ts new file mode 100644 index 00000000..33e1b67b --- /dev/null +++ b/GPTutor-Backend-v2/src/repositories/FileRepository.ts @@ -0,0 +1,102 @@ +import { PrismaClient } from "@prisma/client"; + +export class FileRepository { + private prisma: PrismaClient; + + constructor(prisma: PrismaClient) { + this.prisma = prisma; + } + + async create(data: { + userId: string; + type: string; + name: string; + url: string; + size: number; + }) { + return this.prisma.file.create({ + data: { + userId: data.userId, + type: data.type, + name: data.name, + url: data.url, + size: data.size, + }, + }); + } + + async findById(id: string) { + return this.prisma.file.findUnique({ + where: { id }, + }); + } + + async findByUserId(userId: string) { + return this.prisma.file.findMany({ + where: { userId }, + orderBy: { createdAt: "desc" }, + }); + } + + async delete(id: string): Promise { + await this.prisma.file.delete({ + where: { id }, + }); + } + + async update( + id: string, + data: { + name?: string; + type?: string; + url?: string; + size?: number; + } + ) { + return this.prisma.file.update({ + where: { id }, + data, + }); + } + + async findByUrl(url: string) { + return this.prisma.file.findFirst({ + where: { url }, + }); + } + + async getFileStats(userId: string): Promise<{ + totalFiles: number; + totalSize: number; + filesByType: Record; + }> { + const files = await this.prisma.file.findMany({ + where: { userId }, + select: { + type: true, + size: true, + }, + }); + + const totalFiles = files.length; + const totalSize = files.reduce( + (sum: number, file: any) => sum + file.size, + 0 + ); + + const filesByType = files.reduce( + (acc: Record, file: any) => { + const type = file.type.split("/")[0]; // Получаем основной тип (image, application, etc.) + acc[type] = (acc[type] || 0) + 1; + return acc; + }, + {} as Record + ); + + return { + totalFiles, + totalSize, + filesByType, + }; + } +} diff --git a/GPTutor-Backend-v2/src/repositories/UserRepository.ts b/GPTutor-Backend-v2/src/repositories/UserRepository.ts new file mode 100644 index 00000000..0ed4057f --- /dev/null +++ b/GPTutor-Backend-v2/src/repositories/UserRepository.ts @@ -0,0 +1,80 @@ +import { PrismaClient, User } from "@prisma/client"; +import { randomBytes } from "crypto"; + +export class UserRepository { + private prisma: PrismaClient; + + constructor(prisma: PrismaClient) { + this.prisma = prisma; + } + + private generateApiKey(): string { + // Generate a random string similar to OpenAI API keys + // Format: sk- + 48 characters (mix of letters and numbers) + const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + let result = 'sk-'; + + // Generate 48 random characters + for (let i = 0; i < 48; i++) { + result += chars.charAt(Math.floor(Math.random() * chars.length)); + } + + return result; + } + + async findByVkId(vkId: string): Promise { + return this.prisma.user.findUnique({ + where: { vkId }, + }); + } + + async create(data: { + vkId: string; + balance?: number; + isActive?: boolean; + }): Promise { + return this.prisma.user.create({ + data: { + vkId: data.vkId, + balance: data.balance ?? 0.0, + isActive: data.isActive ?? true, + apiKey: this.generateApiKey(), + }, + }); + } + + async findByApiKey(apiKey: string): Promise { + return this.prisma.user.findUnique({ + where: { apiKey }, + }); + } + + async updateBalance(userId: string, newBalance: number): Promise { + return this.prisma.user.update({ + where: { id: userId }, + data: { balance: newBalance }, + }); + } + + async decreaseBalance(userId: string, amount: number): Promise { + const user = await this.prisma.user.findUnique({ where: { id: userId } }); + if (!user) { + throw new Error("User not found"); + } + + const newBalance = user.balance - amount * 2; + if (newBalance < 0) { + throw new Error("Insufficient balance"); + } + + return this.updateBalance(userId, newBalance); + } + + async updateApiKey(userId: string): Promise { + const newApiKey = this.generateApiKey(); + return this.prisma.user.update({ + where: { id: userId }, + data: { apiKey: newApiKey }, + }); + } +} diff --git a/GPTutor-Backend-v2/src/services/AuthService.ts b/GPTutor-Backend-v2/src/services/AuthService.ts new file mode 100644 index 00000000..54677ea8 --- /dev/null +++ b/GPTutor-Backend-v2/src/services/AuthService.ts @@ -0,0 +1,46 @@ +import { validateVKSignature, extractVKUserData, VKUserData } from '../utils/vkAuth'; +import { UserRepository } from '../repositories/UserRepository'; +import { User } from '@prisma/client'; + +export class AuthService { + private userRepository: UserRepository; + private vkAppId: string; + private vkSecretKey: string; + + constructor(userRepository: UserRepository, vkAppId: string, vkSecretKey: string) { + this.userRepository = userRepository; + this.vkAppId = vkAppId; + this.vkSecretKey = vkSecretKey; + } + + async authorizeVKUser(token: string): Promise<{ vkData: VKUserData, dbUser: User }> { + if (!validateVKSignature(token, this.vkSecretKey)) { + throw new Error('Invalid VK signature'); + } + + const userData = extractVKUserData(token); + if (!userData || !userData.vk_user_id) { + throw new Error('Invalid VK user data'); + } + + if (userData.vk_app_id !== this.vkAppId) { + throw new Error('Invalid VK app ID'); + } + + let user = await this.userRepository.findByVkId(userData.vk_user_id); + + if (!user) { + user = await this.userRepository.create({ vkId: userData.vk_user_id }); + console.log(`Created new user with VK ID: ${userData.vk_user_id}`); + } + + return { vkData: userData, dbUser: user }; + } + + async updateUserToken(userId: string): Promise { + const user = await this.userRepository.updateApiKey(userId); + console.log(`Updated API key for user: ${userId}`); + return user; + } +} + diff --git a/GPTutor-Backend-v2/src/services/FilesService.ts b/GPTutor-Backend-v2/src/services/FilesService.ts new file mode 100644 index 00000000..b3f04673 --- /dev/null +++ b/GPTutor-Backend-v2/src/services/FilesService.ts @@ -0,0 +1,179 @@ +import sharp from "sharp"; +import { compress } from "compress-pdf"; +import EasyYandexS3 from "easy-yandex-s3"; +import crypto from "crypto"; +import { S3 } from "aws-sdk"; + +const s3 = new EasyYandexS3({ + auth: { + accessKeyId: process.env.YANDEX_ACCESS_KEY_ID!, + secretAccessKey: process.env.YANDEX_SECRET_ACCESS_KEY!, + }, + httpOptions: { + timeout: 60000, + }, + Bucket: process.env.YANDEX_BUCKET!, + debug: process.env.NODE_ENV === "development", +}); + +export class FilesService { + private getExtension(fileName: string): string { + const splitFileName = fileName.split("."); + return splitFileName[splitFileName.length - 1]; + } + + private getFileWithExtension(name: string, originalFileName: string): string { + return `${name}.${this.getExtension(originalFileName)}`; + } + + private async optimizePhotos( + arrayBuffer: ArrayBuffer, + fileName: string + ): Promise { + try { + let extension = this.getExtension(fileName); + + if (extension === "jpg") { + extension = "jpeg"; + } + + const createdSharp = sharp(arrayBuffer); + if (extension in createdSharp) { + // @ts-ignore + return await createdSharp[extension]({ quality: 60 }).toBuffer(); + } + + return Buffer.from(arrayBuffer); + } catch (error) { + console.log("Error optimizing photo:", error); + return Buffer.from(arrayBuffer); + } + } + + private async optimizeAttachment( + arrayBuffer: ArrayBuffer, + fileName: string + ): Promise { + const typeFile = this.determineFileType(fileName); + + if (typeFile === "photo") { + return await this.optimizePhotos(arrayBuffer, fileName); + } + + if (typeFile === "text") { + return Buffer.from(arrayBuffer).toString("utf-8"); + } + + const extension = this.getExtension(fileName); + + if (extension === "pdf") { + return await compress(Buffer.from(arrayBuffer)); + } + + if (extension === "pptx") { + return Buffer.from(arrayBuffer); + } + + return arrayBuffer; + } + + private determineFileType(filename: string): "photo" | "document" | "text" { + if (filename.length === 0) { + throw new Error("Invalid filename: Must be a non-empty string."); + } + + const photoExtensions: string[] = [ + "jpg", + "jpeg", + "png", + "gif", + "bmp", + "svg", + "webp", + "tiff", + "tif", + ]; + + const documentExtensions: string[] = [ + "pdf", + "doc", + "docx", + "xls", + "xlsx", + "csv", + ]; + + const textExtensions: string[] = [ + "txt", + "js", + "html", + "css", + "json", + "xml", + "md", + "log", + "py", + "java", + "c", + "cpp", + "h", + "sh", + "config", + "conf", + "ini", + "yml", + "yaml", + "sql", + ]; + + const dotIndex: number = filename.lastIndexOf("."); + + if (dotIndex === -1 || dotIndex === filename.length - 1) { + throw new Error(`Unknown file type: '${filename}' has no extension.`); + } + + const extension: string = filename.slice(dotIndex + 1).toLowerCase(); + + if (photoExtensions.includes(extension)) { + return "photo"; + } else if (documentExtensions.includes(extension)) { + return "document"; + } else if (textExtensions.includes(extension)) { + return "text"; + } else { + throw new Error( + `Unknown or unsupported file type with extension '.${extension}'.` + ); + } + } + + async uploadFile( + arrayBuffer: ArrayBuffer | string | Buffer | Uint8Array, + name: string + ): Promise { + return (await s3.Upload( + { + //@ts-ignore + buffer: arrayBuffer, + name: this.getFileWithExtension(crypto.randomUUID(), name), + }, + "/" + )) as S3.ManagedUpload.SendData; + } + + async optimizeAndUploadFile( + arrayBuffer: ArrayBuffer, + fileName: string + ): Promise<{ + url: string; + optimizedData: ArrayBuffer | Buffer | string | Uint8Array; + }> { + const optimizedData = await this.optimizeAttachment(arrayBuffer, fileName); + const uploadResult = await this.uploadFile(optimizedData, fileName); + + return { + url: uploadResult.Location, + optimizedData, + }; + } +} diff --git a/GPTutor-Backend-v2/src/services/LLMCostEvaluate.ts b/GPTutor-Backend-v2/src/services/LLMCostEvaluate.ts new file mode 100644 index 00000000..c4f733fa --- /dev/null +++ b/GPTutor-Backend-v2/src/services/LLMCostEvaluate.ts @@ -0,0 +1,188 @@ +import { + OpenRouterModel, + OpenRouterApiResponse, + CostCalculation, + UsageParams, +} from "../types/openrouter"; + +export class LLMCostEvaluate { + private models: OpenRouterModel[] = []; + private usdToRubRate: number; + private readonly OPENROUTER_API_URL = "https://openrouter.ai/api/v1/models"; + + constructor(usdToRubRate: number = 100) { + this.usdToRubRate = usdToRubRate; + } + + async initialize(): Promise { + try { + console.log("🔄 Loading OpenRouter models..."); + + const response = await fetch(this.OPENROUTER_API_URL); + if (!response.ok) { + throw new Error( + `Failed to fetch models: ${response.status} ${response.statusText}` + ); + } + + const data = (await response.json()) as OpenRouterApiResponse; + this.models = data.data; + + console.log(`✅ Loaded ${this.models.length} OpenRouter models`); + } catch (error) { + console.error("❌ Failed to load OpenRouter models:", error); + throw error; + } + } + + getAllModels(): OpenRouterModel[] { + return this.models; + } + + getModelById(modelId: string): OpenRouterModel | null { + return this.models.find((model) => model.id === modelId) || null; + } + + searchModelsByName(searchTerm: string): OpenRouterModel[] { + const term = searchTerm.toLowerCase(); + return this.models.filter( + (model) => + model.name.toLowerCase().includes(term) || + model.id.toLowerCase().includes(term) + ); + } + + calculateCost(cost: number): number { + return Math.round(cost * this.usdToRubRate * 10000) / 10000; + } + + getOpenAIModels(): OpenRouterModel[] { + return this.models.filter((model) => model.id.startsWith("openai/")); + } + + getAnthropicModels(): OpenRouterModel[] { + return this.models.filter((model) => model.id.startsWith("anthropic/")); + } + + getGoogleModels(): OpenRouterModel[] { + return this.models.filter((model) => model.id.startsWith("google/")); + } + + setUsdToRubRate(rate: number): void { + this.usdToRubRate = rate; + console.log(`💱 USD to RUB rate updated: ${rate}`); + } + + getUsdToRubRate(): number { + return this.usdToRubRate; + } + + getStats(): any { + const totalModels = this.models.length; + const openaiCount = this.getOpenAIModels().length; + const anthropicCount = this.getAnthropicModels().length; + const googleCount = this.getGoogleModels().length; + const otherCount = totalModels - openaiCount - anthropicCount - googleCount; + + return { + totalModels, + providers: { + openai: openaiCount, + anthropic: anthropicCount, + google: googleCount, + other: otherCount, + }, + lastUpdated: new Date().toISOString(), + usdToRubRate: this.usdToRubRate, + }; + } + + getModelsWithRubPricing(searchTerm?: string, provider?: string): any[] { + let filteredModels = this.models; + + if (searchTerm) { + const term = searchTerm.toLowerCase(); + filteredModels = filteredModels.filter( + (model) => + model.name.toLowerCase().includes(term) || + model.id.toLowerCase().includes(term) || + model.description.toLowerCase().includes(term) + ); + } + + // Фильтрация по провайдеру + if (provider) { + filteredModels = filteredModels.filter((model) => + model.id.toLowerCase().startsWith(`${provider.toLowerCase()}/`) + ); + } + + // Преобразование цен в рубли + return filteredModels.map((model) => ({ + ...model, + pricing: { + prompt: this.calculateCost(parseFloat(model.pricing.prompt)), + completion: this.calculateCost(parseFloat(model.pricing.completion)), + request: this.calculateCost(parseFloat(model.pricing.request)), + image: this.calculateCost(parseFloat(model.pricing.image)), + web_search: this.calculateCost(parseFloat(model.pricing.web_search)), + internal_reasoning: this.calculateCost( + parseFloat(model.pricing.internal_reasoning) + ), + input_cache_read: model.pricing.input_cache_read + ? this.calculateCost(parseFloat(model.pricing.input_cache_read)) + : undefined, + input_cache_write: model.pricing.input_cache_write + ? this.calculateCost(parseFloat(model.pricing.input_cache_write)) + : undefined, + }, + })); + } + + getCheapestModels( + limit: number = 10, + tokenType: "prompt" | "completion" = "prompt" + ): any[] { + const modelsWithRubPricing = this.getModelsWithRubPricing(); + + return modelsWithRubPricing + .sort((a, b) => a.pricing_rub[tokenType] - b.pricing_rub[tokenType]) + .slice(0, limit); + } + + getModelsInPriceRange( + minPrice: number, + maxPrice: number, + tokenType: "prompt" | "completion" = "prompt" + ): any[] { + return this.getModelsWithRubPricing().filter( + (model) => + model.pricing_rub[tokenType] >= minPrice && + model.pricing_rub[tokenType] <= maxPrice + ); + } + + getModelsByProviders(providers: string[]): any[] { + return this.getModelsWithRubPricing().filter((model) => + providers.some((provider) => + model.id.toLowerCase().startsWith(`${provider.toLowerCase()}/`) + ) + ); + } + + getPopularProviderModels(): any[] { + const popularProviders = [ + "x-ai", + "deepseek", + "google", + "qwen", + "perplexity", + "mistralai", + "openai", + ]; + + return this.getModelsByProviders(popularProviders).filter(model => + !model.name.toLowerCase().includes(':free') + ); + } +} diff --git a/GPTutor-Backend-v2/src/services/LoggerService.ts b/GPTutor-Backend-v2/src/services/LoggerService.ts new file mode 100644 index 00000000..449c310d --- /dev/null +++ b/GPTutor-Backend-v2/src/services/LoggerService.ts @@ -0,0 +1,272 @@ +import winston from "winston"; +import DailyRotateFile from "winston-daily-rotate-file"; +import path from "path"; + +export class LoggerService { + private logger: winston.Logger; + private static instance: LoggerService; + + // Safe JSON stringify that handles circular references + private static safeStringify(obj: any, space?: number): string { + const seen = new WeakSet(); + return JSON.stringify(obj, (key, val) => { + if (val != null && typeof val === "object") { + if (seen.has(val)) { + return "[Circular]"; + } + seen.add(val); + } + return val; + }, space); + } + + private constructor() { + this.logger = this.createLogger(); + } + + public static getInstance(): LoggerService { + if (!LoggerService.instance) { + LoggerService.instance = new LoggerService(); + } + return LoggerService.instance; + } + + private createLogger(): winston.Logger { + const logDir = path.join(process.cwd(), "logs"); + + // Custom format for better readability + const customFormat = winston.format.combine( + winston.format.timestamp({ + format: "YYYY-MM-DD HH:mm:ss", + }), + winston.format.errors({ stack: true }), + winston.format.printf( + ({ + timestamp, + level, + message, + service, + userId, + requestId, + ...meta + }) => { + let logMessage = `[${timestamp}] ${level.toUpperCase()}`; + + if (service) logMessage += ` [${service}]`; + if (requestId) logMessage += ` [ReqID: ${requestId}]`; + if (userId) logMessage += ` [User: ${userId}]`; + + logMessage += `: ${message}`; + + const metaStr = Object.keys(meta).length + ? ` ${LoggerService.safeStringify(meta)}` + : ""; + return logMessage + metaStr; + } + ) + ); + + const consoleFormat = winston.format.combine( + winston.format.colorize(), + customFormat + ); + + return winston.createLogger({ + level: process.env.LOG_LEVEL || "info", + format: customFormat, + defaultMeta: { service: "gptutor-backend" }, + transports: [ + new winston.transports.Console({ + format: consoleFormat, + }), + + new DailyRotateFile({ + filename: path.join(logDir, "error-%DATE%.log"), + datePattern: "YYYY-MM-DD", + level: "error", + maxSize: "20m", + maxFiles: "14d", + format: winston.format.combine( + winston.format.timestamp(), + winston.format.json() + ), + }), + + new DailyRotateFile({ + filename: path.join(logDir, "combined-%DATE%.log"), + datePattern: "YYYY-MM-DD", + maxSize: "20m", + maxFiles: "30d", + format: winston.format.combine( + winston.format.timestamp(), + winston.format.json() + ), + }), + + // API requests log file + new DailyRotateFile({ + filename: path.join(logDir, "api-%DATE%.log"), + datePattern: "YYYY-MM-DD", + maxSize: "20m", + maxFiles: "30d", + level: "info", + format: winston.format.combine( + winston.format.timestamp(), + winston.format.json() + ), + }), + ], + }); + } + + // Basic logging methods + public debug(message: string, meta?: any): void { + this.logger.debug(message, meta); + } + + public info(message: string, meta?: any): void { + this.logger.info(message, meta); + } + + public warn(message: string, meta?: any): void { + this.logger.warn(message, meta); + } + + public error(message: string, error?: Error | any, meta?: any): void { + if (error instanceof Error) { + this.logger.error(message, { + error: error.message, + stack: error.stack, + ...meta, + }); + } else { + this.logger.error(message, { error, ...meta }); + } + } + + // Specialized logging methods + public apiRequest( + method: string, + url: string, + userId?: string, + meta?: any + ): void { + this.logger.info(`${method} ${url}`, { + type: "api", + service: "api", + method, + url, + userId, + ...meta, + }); + } + + public apiResponse( + method: string, + url: string, + statusCode: number, + duration: number, + userId?: string, + meta?: any + ): void { + this.logger.info(`${method} ${url} - ${statusCode} (${duration}ms)`, { + type: "api", + service: "api", + method, + url, + statusCode, + duration, + userId, + ...meta, + }); + } + + public llmRequest( + model: string, + userId: string, + tokens?: number, + cost?: number, + meta?: any + ): void { + this.logger.info(`LLM Request: ${model}`, { + type: "llm", + service: "llm", + model, + userId, + tokens, + cost, + ...meta, + }); + } + + public llmResponse( + model: string, + userId: string, + tokens: number, + cost: number, + duration: number, + meta?: any + ): void { + this.logger.info( + `LLM Response: ${model} - ${tokens} tokens, ${cost} RUB (${duration}ms)`, + { + type: "llm", + service: "llm", + model, + userId, + tokens, + cost, + duration, + ...meta, + } + ); + } + + public auth( + action: string, + userId?: string, + success: boolean = true, + meta?: any + ): void { + const level = success ? "info" : "warn"; + this.logger[level](`Auth ${action}: ${success ? "SUCCESS" : "FAILED"}`, { + type: "auth", + service: "auth", + action, + userId, + success, + ...meta, + }); + } + + public balance( + action: string, + userId: string, + amount: number, + newBalance: number, + meta?: any + ): void { + this.logger.info(`Balance ${action}: ${amount} RUB`, { + type: "balance", + service: "balance", + action, + userId, + amount, + newBalance, + ...meta, + }); + } + + // Create child logger with additional context + public child(defaultMeta: any): winston.Logger { + return this.logger.child(defaultMeta); + } + + // Get the underlying winston logger + public getWinstonLogger(): winston.Logger { + return this.logger; + } +} + +// Export singleton instance +export const logger = LoggerService.getInstance(); diff --git a/GPTutor-Backend-v2/src/services/OpenRouterService.ts b/GPTutor-Backend-v2/src/services/OpenRouterService.ts new file mode 100644 index 00000000..3862cd6b --- /dev/null +++ b/GPTutor-Backend-v2/src/services/OpenRouterService.ts @@ -0,0 +1,65 @@ +import OpenAI from "openai"; +import type { + ChatCompletion, + ChatCompletionCreateParams, +} from "openai/resources/chat/completions"; +import { APIPromise } from "openai/src/core/api-promise"; +import { Stream } from "openai/src/core/streaming"; +import { ChatCompletionChunk } from "openai/src/resources/chat/completions/completions"; + +export class OpenRouterService { + private client: OpenAI; + + constructor(apiKey: string) { + this.client = new OpenAI({ + apiKey: apiKey, + baseURL: "https://openrouter.ai/api/v1", + defaultHeaders: { + "HTTP-Referer": "http://localhost:3001", + "X-Title": "GPTutor API v2", + }, + }); + } + + async createCompletion( + params: ChatCompletionCreateParams + ): Promise { + try { + const completion = await this.client.chat.completions.create({ + ...params, + stream: false, + usage: { include: true }, + } as any); + return completion as ChatCompletion; + } catch (error) { + console.error("OpenRouter API request failed:", error); + throw error; + } + } + + async createCompletionStream(params: ChatCompletionCreateParams) { + try { + //@ts-ignore + return this.client.chat.completions.create({ + ...params, + stream: true, + usage: { + include: true, + }, + }); + } catch (error) { + console.error("OpenRouter API stream request failed:", error); + throw error; + } + } + + async getModels() { + try { + const models = await this.client.models.list(); + return models; + } catch (error) { + console.error("Failed to get models from OpenRouter:", error); + throw error; + } + } +} diff --git a/GPTutor-Backend-v2/src/types/openrouter.ts b/GPTutor-Backend-v2/src/types/openrouter.ts new file mode 100644 index 00000000..c340950d --- /dev/null +++ b/GPTutor-Backend-v2/src/types/openrouter.ts @@ -0,0 +1,68 @@ +export interface OpenRouterPricing { + prompt: string; // Cost per input token + completion: string; // Cost per output token + request: string; // Fixed cost per API request + image: string; // Cost per image input + web_search: string; // Cost per web search operation + internal_reasoning: string; // Cost for internal reasoning tokens + input_cache_read?: string; // Cost per cached input token read + input_cache_write?: string; // Cost per cached input token write +} + +export interface OpenRouterArchitecture { + modality: string; + input_modalities: string[]; + output_modalities: string[]; + tokenizer: string; + instruct_type: string | null; +} + +export interface OpenRouterTopProvider { + context_length: number; + max_completion_tokens: number; + is_moderated: boolean; +} + +export interface OpenRouterDefaultParameters { + temperature: number | null; + top_p: number | null; + frequency_penalty: number | null; +} + +export interface OpenRouterModel { + id: string; + canonical_slug: string; + hugging_face_id: string; + name: string; + created: number; + description: string; + context_length: number; + architecture: OpenRouterArchitecture; + pricing: OpenRouterPricing; + top_provider: OpenRouterTopProvider; + per_request_limits: any; + supported_parameters: string[]; + default_parameters: OpenRouterDefaultParameters; +} + +export interface OpenRouterApiResponse { + data: OpenRouterModel[]; +} + +export interface CostCalculation { + promptCostRub: number; + completionCostRub: number; + requestCostRub: number; + imageCostRub: number; + totalCostRub: number; +} + +export interface UsageParams { + promptTokens?: number; + completionTokens?: number; + images?: number; + requests?: number; +} + + + diff --git a/GPTutor-Backend-v2/src/utils/vkAuth.ts b/GPTutor-Backend-v2/src/utils/vkAuth.ts new file mode 100644 index 00000000..e205bed0 --- /dev/null +++ b/GPTutor-Backend-v2/src/utils/vkAuth.ts @@ -0,0 +1,131 @@ +import * as crypto from "crypto"; +import { UserRepository } from "../repositories/UserRepository"; + +export function validateVKSignature( + queryString: string, + secretKey: string +): boolean { + try { + // Handle both full URL and query string + let params: URLSearchParams; + + if (queryString.startsWith("http")) { + // Full URL + const url = new URL(queryString); + params = new URLSearchParams(url.search); + } else { + // Query string only + params = new URLSearchParams(queryString); + } + + const sign = params.get("sign"); + if (!sign) return false; + + params.delete("sign"); + + const sortedParams = Array.from(params.entries()) + .sort(([a], [b]) => a.localeCompare(b)) + .map(([key, value]) => `${key}=${value}`) + .join("&"); + + const hmac = crypto.createHmac("sha256", secretKey); + hmac.update(sortedParams); + const computedSign = hmac.digest("base64url"); + + // Debug logging + console.log("VK Signature validation:"); + console.log("Sorted params:", sortedParams); + console.log("Received sign:", sign); + console.log("Computed sign:", computedSign); + console.log("Signatures match:", computedSign === sign); + + return computedSign === sign; + } catch (error) { + console.error("VK signature validation error:", error); + return false; + } +} + +export function extractVKUserData(queryString: string) { + try { + // Handle both full URL and query string + let params: URLSearchParams; + + if (queryString.startsWith("http")) { + // Full URL + const url = new URL(queryString); + params = new URLSearchParams(url.search); + } else { + // Query string only + params = new URLSearchParams(queryString); + } + + return { + vk_user_id: params.get("vk_user_id"), + vk_app_id: params.get("vk_app_id"), + vk_is_app_user: params.get("vk_is_app_user"), + vk_language: params.get("vk_language"), + vk_platform: params.get("vk_platform"), + vk_ts: params.get("vk_ts"), + }; + } catch (error) { + console.error("Error extracting VK user data:", error); + return null; + } +} + +export interface VKUserData { + vk_user_id: string | null; + vk_app_id: string | null; + vk_is_app_user: string | null; + vk_language: string | null; + vk_platform: string | null; + vk_ts: string | null; +} + +export async function validateApiKey( + apiKey: string, + userRepository: UserRepository +): Promise { + try { + if (!apiKey.startsWith("sk-")) { + return null; + } + + const user = await userRepository.findByApiKey(apiKey); + + if (!user || !user.isActive) { + return null; + } + + return user; + } catch (error) { + console.error("API key validation error:", error); + return null; + } +} + +export async function authenticateUser( + authHeader: string | undefined, + vkSecretKey: string, + userRepository: UserRepository +): Promise { + if (authHeader && authHeader.startsWith("Bearer ")) { + const apiKey = authHeader.substring(7); + if (apiKey.startsWith("sk-")) { + const user = await validateApiKey(apiKey, userRepository); + if (user) { + return { user, authType: "api_key" }; + } + } + + if (validateVKSignature(apiKey, vkSecretKey)) { + const vkData = extractVKUserData(apiKey); + if (vkData && vkData.vk_user_id) { + return { user: vkData, authType: "vk" }; + } + } + } + + return null; +} diff --git a/GPTutor-Backend-v2/tsconfig.json b/GPTutor-Backend-v2/tsconfig.json new file mode 100644 index 00000000..b7354da4 --- /dev/null +++ b/GPTutor-Backend-v2/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ES2020", + "lib": ["ES2020"], + "module": "commonjs", + "moduleResolution": "node", + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "outDir": "./dist", + "rootDir": "./src", + "resolveJsonModule": true, + "declaration": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} + diff --git a/GPTutor-Frontend-v2/.eslintrc.cjs b/GPTutor-Frontend-v2/.eslintrc.cjs new file mode 100644 index 00000000..b1e978da --- /dev/null +++ b/GPTutor-Frontend-v2/.eslintrc.cjs @@ -0,0 +1,15 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:react-hooks/recommended', + ], + ignorePatterns: ['dist', '.eslintrc.cjs'], + parser: '@typescript-eslint/parser', + plugins: ['react-refresh'], + rules: { + 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }], + }, +}; diff --git a/GPTutor-Frontend-v2/README.md b/GPTutor-Frontend-v2/README.md new file mode 100644 index 00000000..9f6da18e --- /dev/null +++ b/GPTutor-Frontend-v2/README.md @@ -0,0 +1,55 @@ +# Basic [VK Bridge](https://github.com/VKCOM/vk-bridge) + [VKUI](https://github.com/VKCOM/VKUI) + [VK Miniapps Router](https://github.com/VKCOM/vk-mini-apps-router) app + +Этот шаблон предоставляет базовый код и настройки для создания мини-приложения внутри ВКонтакте. +В качестве сборщика проекта выступает [Vite](https://vite-docs-ru.vercel.app/guide/), подробнее про его конфигурацию и дополнительные плагины можно прочитать [здесь](https://vite-docs-ru.vercel.app/config/) и [здесь](). + +## 🚀 Запуск мини приложения + +Запустите ваш мини апп + +```sh + yarn start +``` + +Перейдите на [devportal](https://dev.vk.com/ru) или в [управление](https://vk.com/apps?act=manage) и создайте новый мини апп. +Вставьте URL на котором работает ваше приложение в настройки, предварительно включив режим разработки. +Теперь можете открыть мини апп, нажав на его иконку. +Список всех созданных вами мини приложений вы сможете найти [тут](https://vk.com/apps?act=manage) или [тут](https://dev.vk.com/ru/admin/apps-list). + +## 🌐 Деплой мини приложения + +Для того чтобы поделиться приложением запущенным на localhost со своими друзьями, вы можете скачать утилиту vk-tunnel и запустить уже подготовленный скрипт из package.json + +```sh +yarn global add @vkontakte/vk-tunnel +yarn run tunnel +``` + +После чего вы получите ссылку, по которой ваше приложение будет доступно с любого устройства, подробнее про vk-tunnel можно прочитать [тут](https://dev.vk.com/ru/libraries/tunnel). + +Для того чтобы захостить ваше приложение на сервера ВКонтакте нужно зайти в vk-hosting-config.json и указать id вашего приложения. Далее можно запустить уже подготовленный скрипт: + +```sh +yarn run deploy +``` + +После чего, вы получите бессрочную ссылку на ваш мини апп. + +## 🗂️ Предустановленные библиотеки + +Мы подготовили для вас набор пакетов, с которыми вам будет легко начать разрабатывать мини аппы +| Пакет | Назначение | +| ------ | ------ | +| [vk-bridge](https://dev.vk.com/ru/mini-apps/bridge) | Библиотека для отправки команд и обмена данными с платформой ВКонтакте. | +| [VKUI](https://vkcom.github.io/VKUI/) | Библиотека React-компонентов для создания мини-приложений в стиле ВКонтакте. | +| [vk-bridge-react](https://www.npmjs.com/package/@vkontakte/vk-bridge-react) | Пакет, который даёт возможность использовать события библиотеки VK Bridge в React-приложениях. | +| [vk-mini-apps-router](https://dev.vk.com/ru/libraries/router) | Библиотека для маршрутизации и навигации в мини-приложениях, созданных с помощью VKUI. | +| [icons](https://vkcom.github.io/icons/) | Набор иконок для использования в компонентах VKUI. | +| [vk-miniapps-deploy](https://dev.vk.com/ru/mini-apps/development/hosting) | Пакет для размещения файлов мини-приложения на хостинге ВКонтакте. | +| [eruda](https://www.npmjs.com/package/eruda) | Консоль для мобильного браузера| + +## 📎 Полезные ссылки + +[Dev портал разработчиков](https://dev.vk.com/ru) +[Пример мини приложения](https://dev.vk.com/ru/mini-apps/examples/shop) +[Если столкнулись с проблемами](https://github.com/VKCOM/create-vk-mini-app/issues) diff --git a/GPTutor-Frontend-v2/index.html b/GPTutor-Frontend-v2/index.html new file mode 100644 index 00000000..63011420 --- /dev/null +++ b/GPTutor-Frontend-v2/index.html @@ -0,0 +1,16 @@ + + + + + + + VK Mini App Boilerplate + + +
+ + + diff --git a/GPTutor-Frontend-v2/package-lock.json b/GPTutor-Frontend-v2/package-lock.json new file mode 100644 index 00000000..ee14c3c9 --- /dev/null +++ b/GPTutor-Frontend-v2/package-lock.json @@ -0,0 +1,7433 @@ +{ + "name": "gptutor-frontend-v2", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "gptutor-frontend-v2", + "version": "0.0.0", + "dependencies": { + "@vkontakte/icons": "^3.1.1", + "@vkontakte/vk-bridge": "^2.13.0", + "@vkontakte/vk-bridge-react": "^1.0.1", + "@vkontakte/vk-mini-apps-router": "^1.7.6", + "@vkontakte/vkui": "^7.0.0", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@types/react": "^18.2.43", + "@types/react-dom": "^18.2.17", + "@typescript-eslint/eslint-plugin": "^6.14.0", + "@typescript-eslint/parser": "^6.14.0", + "@vitejs/plugin-legacy": "^5.3.1", + "@vitejs/plugin-react": "^4.2.1", + "@vkontakte/vk-miniapps-deploy": "^0.1.6", + "@vkontakte/vk-tunnel": "^0.2.4", + "eruda": "^3.0.1", + "esbuild": "~0.20.0", + "eslint": "^8.55.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.5", + "terser": "^5.4.0", + "typescript": "^5.2.2", + "vite": "^5.0.8" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", + "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", + "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.4", + "@babel/types": "^7.28.4", + "@jridgewell/remapping": "^2.3.5", + "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/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "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, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.3.tgz", + "integrity": "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.3", + "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, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", + "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "regexpu-core": "^6.2.0", + "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, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", + "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "debug": "^4.4.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.10" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", + "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.3.tgz", + "integrity": "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.3", + "@babel/types": "^7.28.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.4" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", + "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", + "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "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.27.1", + "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.27.1.tgz", + "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", + "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz", + "integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", + "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "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, + "license": "MIT", + "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.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", + "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", + "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", + "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.4.tgz", + "integrity": "sha512-1yxmvN0MJHOhPVmAsmoW5liWwoILobu/d/ShymZmj867bAdxGbehIrew1DuLpw2Ukv+qDSSPQdYW1dLNE7t11A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", + "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz", + "integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.3", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", + "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-globals": "^7.28.0", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/traverse": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", + "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/template": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz", + "integrity": "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", + "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", + "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", + "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", + "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", + "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", + "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", + "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", + "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", + "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", + "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", + "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", + "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", + "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", + "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", + "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/traverse": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", + "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", + "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", + "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", + "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", + "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", + "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", + "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", + "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", + "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", + "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", + "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", + "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", + "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", + "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", + "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.3.tgz", + "integrity": "sha512-ROiDcM+GbYVPYBOeCR6uBXKkQpBExLl8k9HO1ygXEyds39j+vCCsjmj7S8GOniZQlEs81QlkdJZe76IpLSiqpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.0", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.27.1", + "@babel/plugin-syntax-import-attributes": "^7.27.1", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.28.0", + "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.28.0", + "@babel/plugin-transform-class-properties": "^7.27.1", + "@babel/plugin-transform-class-static-block": "^7.28.3", + "@babel/plugin-transform-classes": "^7.28.3", + "@babel/plugin-transform-computed-properties": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-explicit-resource-management": "^7.28.0", + "@babel/plugin-transform-exponentiation-operator": "^7.27.1", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.27.1", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", + "@babel/plugin-transform-numeric-separator": "^7.27.1", + "@babel/plugin-transform-object-rest-spread": "^7.28.0", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/plugin-transform-private-methods": "^7.27.1", + "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.28.3", + "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "core-js-compat": "^3.43.0", + "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, + "license": "ISC", + "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, + "license": "MIT", + "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/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", + "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.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, + "license": "MIT", + "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.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", + "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.4" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "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.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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, + "license": "Apache-2.0", + "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, + "license": "BSD-3-Clause" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@remix-run/router": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.0.tgz", + "integrity": "sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.3.tgz", + "integrity": "sha512-h6cqHGZ6VdnwliFG1NXvMPTy/9PS3h8oLh7ImwR+kl+oYnQizgjxsONmmPSb2C66RksfkfIxEVtDSEcJiO0tqw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.3.tgz", + "integrity": "sha512-wd+u7SLT/u6knklV/ifG7gr5Qy4GUbH2hMWcDauPFJzmCZUAJ8L2bTkVXC2niOIxp8lk3iH/QX8kSrUxVZrOVw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.3.tgz", + "integrity": "sha512-lj9ViATR1SsqycwFkJCtYfQTheBdvlWJqzqxwc9f2qrcVrQaF/gCuBRTiTolkRWS6KvNxSk4KHZWG7tDktLgjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.3.tgz", + "integrity": "sha512-+Dyo7O1KUmIsbzx1l+4V4tvEVnVQqMOIYtrxK7ncLSknl1xnMHLgn7gddJVrYPNZfEB8CIi3hK8gq8bDhb3h5A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.3.tgz", + "integrity": "sha512-u9Xg2FavYbD30g3DSfNhxgNrxhi6xVG4Y6i9Ur1C7xUuGDW3banRbXj+qgnIrwRN4KeJ396jchwy9bCIzbyBEQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.3.tgz", + "integrity": "sha512-5M8kyi/OX96wtD5qJR89a/3x5x8x5inXBZO04JWhkQb2JWavOWfjgkdvUqibGJeNNaz1/Z1PPza5/tAPXICI6A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.3.tgz", + "integrity": "sha512-IoerZJ4l1wRMopEHRKOO16e04iXRDyZFZnNZKrWeNquh5d6bucjezgd+OxG03mOMTnS1x7hilzb3uURPkJ0OfA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.3.tgz", + "integrity": "sha512-ZYdtqgHTDfvrJHSh3W22TvjWxwOgc3ThK/XjgcNGP2DIwFIPeAPNsQxrJO5XqleSlgDux2VAoWQ5iJrtaC1TbA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.3.tgz", + "integrity": "sha512-NcViG7A0YtuFDA6xWSgmFb6iPFzHlf5vcqb2p0lGEbT+gjrEEz8nC/EeDHvx6mnGXnGCC1SeVV+8u+smj0CeGQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.3.tgz", + "integrity": "sha512-d3pY7LWno6SYNXRm6Ebsq0DJGoiLXTb83AIPCXl9fmtIQs/rXoS8SJxxUNtFbJ5MiOvs+7y34np77+9l4nfFMw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.3.tgz", + "integrity": "sha512-3y5GA0JkBuirLqmjwAKwB0keDlI6JfGYduMlJD/Rl7fvb4Ni8iKdQs1eiunMZJhwDWdCvrcqXRY++VEBbvk6Eg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.3.tgz", + "integrity": "sha512-AUUH65a0p3Q0Yfm5oD2KVgzTKgwPyp9DSXc3UA7DtxhEb/WSPfbG4wqXeSN62OG5gSo18em4xv6dbfcUGXcagw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.3.tgz", + "integrity": "sha512-1makPhFFVBqZE+XFg3Dkq+IkQ7JvmUrwwqaYBL2CE+ZpxPaqkGaiWFEWVGyvTwZace6WLJHwjVh/+CXbKDGPmg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.3.tgz", + "integrity": "sha512-OOFJa28dxfl8kLOPMUOQBCO6z3X2SAfzIE276fwT52uXDWUS178KWq0pL7d6p1kz7pkzA0yQwtqL0dEPoVcRWg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.3.tgz", + "integrity": "sha512-jMdsML2VI5l+V7cKfZx3ak+SLlJ8fKvLJ0Eoa4b9/vCUrzXKgoKxvHqvJ/mkWhFiyp88nCkM5S2v6nIwRtPcgg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.3.tgz", + "integrity": "sha512-tPgGd6bY2M2LJTA1uGq8fkSPK8ZLYjDjY+ZLK9WHncCnfIz29LIXIqUgzCR0hIefzy6Hpbe8Th5WOSwTM8E7LA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.3.tgz", + "integrity": "sha512-BCFkJjgk+WFzP+tcSMXq77ymAPIxsX9lFJWs+2JzuZTLtksJ2o5hvgTdIcZ5+oKzUDMwI0PfWzRBYAydAHF2Mw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.3.tgz", + "integrity": "sha512-KTD/EqjZF3yvRaWUJdD1cW+IQBk4fbQaHYJUmP8N4XoKFZilVL8cobFSTDnjTtxWJQ3JYaMgF4nObY/+nYkumA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.3.tgz", + "integrity": "sha512-+zteHZdoUYLkyYKObGHieibUFLbttX2r+58l27XZauq0tcWYYuKUwY2wjeCN9oK1Um2YgH2ibd6cnX/wFD7DuA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.3.tgz", + "integrity": "sha512-of1iHkTQSo3kr6dTIRX6t81uj/c/b15HXVsPcEElN5sS859qHrOepM5p9G41Hah+CTqSh2r8Bm56dL2z9UQQ7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.3.tgz", + "integrity": "sha512-s0hybmlHb56mWVZQj8ra9048/WZTPLILKxcvcq+8awSZmyiSUZjjem1AhU3Tf4ZKpYhK4mg36HtHDOe8QJS5PQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.3.tgz", + "integrity": "sha512-zGIbEVVXVtauFgl3MRwGWEN36P5ZGenHRMgNw88X5wEhEBpq0XrMEZwOn07+ICrwM17XO5xfMZqh0OldCH5VTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@swc/helpers": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "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, + "license": "MIT", + "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.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.24", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.24.tgz", + "integrity": "sha512-0dLEBsA1kI3OezMBF8nSsb7Nk19ZnsyE1LLhB8r27KbgU5H4pvuqZLdtE+aUkJVoXgTVuA+iLIwmZ0TuK4tx6A==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@types/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@vitejs/plugin-legacy": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-legacy/-/plugin-legacy-5.4.3.tgz", + "integrity": "sha512-wsyXK9mascyplcqvww1gA1xYiy29iRHfyciw+a0t7qRNdzX6PdfSWmOoCi74epr87DujM+5J+rnnSv+4PazqVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.8", + "@babel/preset-env": "^7.25.8", + "browserslist": "^4.24.0", + "browserslist-to-esbuild": "^2.1.1", + "core-js": "^3.38.1", + "magic-string": "^0.30.12", + "regenerator-runtime": "^0.14.1", + "systemjs": "^6.15.1" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "peerDependencies": { + "terser": "^5.4.0", + "vite": "^5.0.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/@vkontakte/icons": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/@vkontakte/icons/-/icons-3.19.0.tgz", + "integrity": "sha512-XuEVblOpbFamvRzUXDrKFNnt6QOeNJfqn/oTE97ZonFb+AIew+cB/6h7S0Y4agyvDvHqxI2WdJmtmTe7w1BsEw==", + "license": "MIT", + "dependencies": { + "@swc/helpers": "^0.5.17", + "@vkontakte/icons-sprite": "^3.1.1" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@vkontakte/icons-sprite": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@vkontakte/icons-sprite/-/icons-sprite-3.1.1.tgz", + "integrity": "sha512-qFrTDmijeZpmcP779DRBGfBr9Wn5sdPrP39ZL/4fG5pg/D6+Fc6sYuC5N088vOVrGP6oro07B45liJrfhv5LfA==", + "license": "MIT", + "dependencies": { + "@swc/helpers": "^0.5.17" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@vkontakte/vk-bridge": { + "version": "2.15.9", + "resolved": "https://registry.npmjs.org/@vkontakte/vk-bridge/-/vk-bridge-2.15.9.tgz", + "integrity": "sha512-YonvPu/ozRXm/iE1vHfZLKJwCzaAol/ZnQ/zfFQFnRlkQh5uWQOuif3GdSFUrVYYNvlMY752Zl0lWVStnhSKVQ==", + "license": "MIT" + }, + "node_modules/@vkontakte/vk-bridge-react": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@vkontakte/vk-bridge-react/-/vk-bridge-react-1.1.0.tgz", + "integrity": "sha512-yHu/1q7/p/Wm3Wumj8C+h71VliCIMLB+6AJYUNsKg9PksL76Dl1rw2gfcgNJobd4idFDRL4J4kAMOO6jQIHIGQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "@vkontakte/vk-bridge": "^2.15.1", + "react": "^17.0.0 || ^18.1.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@vkontakte/vk-mini-apps-router": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@vkontakte/vk-mini-apps-router/-/vk-mini-apps-router-1.8.1.tgz", + "integrity": "sha512-Fb1oNmPDOYrRQ8ySG9++ay7E+rgH5TAZV8MeSTqPjeQBpipVxUfRmk4py4IW8omke7gn5sjDJ2fFOXPyUWmUcg==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "^1.13.0" + }, + "peerDependencies": { + "@vkontakte/vk-bridge": "^2.7.2", + "@vkontakte/vkui": "^5.1.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/@vkontakte/vk-miniapps-deploy": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@vkontakte/vk-miniapps-deploy/-/vk-miniapps-deploy-0.1.9.tgz", + "integrity": "sha512-aX9APiMA23u1gVzxUbpuachS6VMMap4WyYyq6ZUxsXFsUNUa0fOgxS092nuM3YDZaw3aml20MRbsh/Gj0NpB+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "async": "^3.2.0", + "chalk": "^3.0.0", + "configstore": "^5.0.0", + "form-data": "^3.0.0", + "fs-extra": "^8.0.1", + "node-fetch": "^2.6.0", + "prompts": "^2.1.0", + "require-module": "^0.1.0", + "zip-a-folder": "0.0.12" + }, + "bin": { + "vk-miniapps-deploy": "bin/vk-miniapps-deploy" + }, + "engines": { + "node": ">=8.10" + } + }, + "node_modules/@vkontakte/vk-tunnel": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@vkontakte/vk-tunnel/-/vk-tunnel-0.2.9.tgz", + "integrity": "sha512-5tMvYkkQEfqRlmaheBoHxbwHZ+R0UJo3eBr4zuCP30yi0HF9AgJf3NwUWWdtzqMpFfW/b55lgSh16Q1j5shSbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "axios": "^1.8.4", + "axios-retry": "^4.4.0", + "chalk": "^3.0.0", + "configstore": "^6.0.0", + "minimist": "^1.2.8", + "pino": "^8.19.0", + "pino-pretty": "^10.3.1", + "prompts": "^2.3.2", + "ws": "^8.16.0" + }, + "bin": { + "vk-tunnel": "bin/vk-tunnel.js" + } + }, + "node_modules/@vkontakte/vk-tunnel/node_modules/configstore": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz", + "integrity": "sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dot-prop": "^6.0.1", + "graceful-fs": "^4.2.6", + "unique-string": "^3.0.0", + "write-file-atomic": "^3.0.3", + "xdg-basedir": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/yeoman/configstore?sponsor=1" + } + }, + "node_modules/@vkontakte/vk-tunnel/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, + "license": "MIT", + "dependencies": { + "type-fest": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vkontakte/vk-tunnel/node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vkontakte/vk-tunnel/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, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vkontakte/vk-tunnel/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, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vkontakte/vk-tunnel/node_modules/xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vkontakte/vkjs": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@vkontakte/vkjs/-/vkjs-2.0.1.tgz", + "integrity": "sha512-VPce+45X7mXpukkLwDaXwFfqfq0NZecoZ3Js3XwXFfhwNanetxMo/6XqG3sV319mxJoAqW8gMQoSv+ExLTlmYg==", + "license": "MIT", + "dependencies": { + "@swc/helpers": "^0.5.0", + "clsx": "^2.1.1" + } + }, + "node_modules/@vkontakte/vkui": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@vkontakte/vkui/-/vkui-7.7.1.tgz", + "integrity": "sha512-GQbSBfpYEHC6V70gPHSVjdY7e7/XM8MeFHFNPYpZTuGTijbY0sC7H06D/NZ/zyxRzPAli7aGuVDOKSvIajh6bQ==", + "license": "MIT", + "dependencies": { + "@swc/helpers": "^0.5.17", + "@vkontakte/icons": "^3.0.0", + "@vkontakte/vkjs": "^2.0.1", + "@vkontakte/vkui-date-fns-tz": "^0.0.6", + "@vkontakte/vkui-floating-ui": "^0.2.7" + }, + "peerDependencies": { + "react": "^18.2.0 || ^19.0.0", + "react-dom": "^18.2.0 || ^19.0.0" + } + }, + "node_modules/@vkontakte/vkui-date-fns-tz": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@vkontakte/vkui-date-fns-tz/-/vkui-date-fns-tz-0.0.6.tgz", + "integrity": "sha512-bC4yscqq+XnSsqJJLOBh1gMePVmS5FttsZv57o/rt1FbJpuDoC666zLnDat2nzCskU7j+oWi8oipfMdh1VLp8w==", + "license": "MIT" + }, + "node_modules/@vkontakte/vkui-floating-ui": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@vkontakte/vkui-floating-ui/-/vkui-floating-ui-0.2.7.tgz", + "integrity": "sha512-4cHwX2pJI4HBZM+Cp/E4f9tDIxU6AimvDEX5WEHGOLUkbCZDiSB2wavsZz128czedpmA/b+AX/l2codwKOhJtA==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.1.6", + "@swc/helpers": "^0.5.17" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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/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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/archiver": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-3.1.1.tgz", + "integrity": "sha512-5Hxxcig7gw5Jod/8Gq0OneVgLYET+oNHcxgWItq4TbhOzRLKNAFUb9edAftiMKXvXfCB0vbGrJdZDNq0dWMsxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "archiver-utils": "^2.1.0", + "async": "^2.6.3", + "buffer-crc32": "^0.2.1", + "glob": "^7.1.4", + "readable-stream": "^3.4.0", + "tar-stream": "^2.1.0", + "zip-stream": "^2.1.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver-utils/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, + "license": "MIT", + "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/archiver-utils/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, + "license": "MIT" + }, + "node_modules/archiver-utils/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, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/archiver/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/archiver/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, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "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, + "license": "Python-2.0" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/axios": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", + "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios-retry": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-4.5.0.tgz", + "integrity": "sha512-aR99oXhpEDGo0UuAlYcn2iGRds30k366Zfa05XWScR9QaQD4JYiP3/1Qt1u7YlefUOK+cn0CcwoL1oefavQUlQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "is-retry-allowed": "^2.2.0" + }, + "peerDependencies": { + "axios": "0.x || 1.x" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", + "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.7", + "@babel/helper-define-polyfill-provider": "^0.6.5", + "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, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", + "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", + "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5" + }, + "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, + "license": "MIT" + }, + "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" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.8.tgz", + "integrity": "sha512-be0PUaPsQX/gPWWgFsdD+GFzaoig5PXaUC1xLkQiYdDnANU8sMnHoQd8JhbJQuvTWrWLyeFN9Imb5Qtfvr4RrQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "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, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/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" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/bl/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, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.26.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.2.tgz", + "integrity": "sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.8.3", + "caniuse-lite": "^1.0.30001741", + "electron-to-chromium": "^1.5.218", + "node-releases": "^2.0.21", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/browserslist-to-esbuild": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/browserslist-to-esbuild/-/browserslist-to-esbuild-2.1.1.tgz", + "integrity": "sha512-KN+mty6C3e9AN8Z5dI1xeN15ExcRNeISoC3g7V0Kax/MMF9MSoYA2G7lkTTcVUFntiEjkpI0HNgqJC1NjdyNUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "meow": "^13.0.0" + }, + "bin": { + "browserslist-to-esbuild": "cli/index.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "browserslist": "*" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "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, + "license": "MIT" + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001745", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001745.tgz", + "integrity": "sha512-ywt6i8FzvdgrrrGbr1jZVObnVv6adj+0if2/omv9cmR2oiZs30zL4DIyaptKcbOrBdOIc74QTMoJvSE2QHh5UQ==", + "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" + } + ], + "license": "CC-BY-4.0" + }, + "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, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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, + "license": "MIT" + }, + "node_modules/compress-commons": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-2.1.1.tgz", + "integrity": "sha512-eVw6n7CnEMFzc3duyFVrQEuY1BlHR3rYsSztyG32ibGMW722i3C6IizEGMFmfMU+A+fALvBIwxN3czffTcdA+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^3.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^2.3.6" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/compress-commons/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, + "license": "MIT", + "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/compress-commons/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, + "license": "MIT" + }, + "node_modules/compress-commons/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, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "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, + "license": "MIT" + }, + "node_modules/configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT" + }, + "node_modules/core-js": { + "version": "3.45.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.45.1.tgz", + "integrity": "sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.45.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.45.1.tgz", + "integrity": "sha512-tqTt5T4PzsMIZ430XGviK4vzYSoeNJ6CXODi6c/voxOT6IZqBht5/EKaSNnYiEjjRYxjVz7DQIsOsY0XNi8PIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.25.3" + }, + "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, + "license": "MIT" + }, + "node_modules/crc": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", + "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.1.0" + } + }, + "node_modules/crc/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" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/crc32-stream": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-3.0.1.tgz", + "integrity": "sha512-mctvpXlbzsvK+6z8kJwSJ5crm7yBwrQMTybJzMw1O4lLGJqjlDCXY2Zw7KheiA6XBEcBmfLx1D88mjRGVJtY9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "crc": "^3.4.4", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">= 6.9.0" + } + }, + "node_modules/crc32-stream/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, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/dateformat": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": 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, + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.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, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.227", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.227.tgz", + "integrity": "sha512-ITxuoPfJu3lsNWUi2lBM2PaBPYgH3uqmxut5vmBxgYvyI4AlJ6P3Cai1O76mOrkJCBzq0IxWg/NtqOrpu/0gKA==", + "dev": true, + "license": "ISC" + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/eruda": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eruda/-/eruda-3.4.3.tgz", + "integrity": "sha512-J2TsF4dXSspOXev5bJ6mljv0dRrxj21wklrDzbvPmYaEmVoC+2psylyRi70nUPFh1mTQfIBsSusUtAMZtUN+/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@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-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, + "license": "MIT", + "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-refresh": { + "version": "0.4.22", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.22.tgz", + "integrity": "sha512-atkAG6QaJMGoTLc4MDAP+rqZcfwQuTIh2IqHWFLy2TEjxr0MOK+5BSG4RzL2564AAPpZkDRsZXAUz68kjnU6Ug==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "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, + "license": "BSD-2-Clause", + "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-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, + "license": "Apache-2.0", + "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.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "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/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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, + "license": "BSD-2-Clause", + "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/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "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==", + "dev": true, + "license": "BSD-2-Clause", + "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==", + "dev": true, + "license": "BSD-2-Clause", + "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, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=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, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/fast-copy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz", + "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "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.8" + }, + "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, + "license": "ISC", + "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==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/fast-redact": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", + "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "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, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.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, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.4.tgz", + "integrity": "sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, + "license": "MIT" + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "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, + "license": "ISC" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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, + "license": "ISC", + "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/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, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/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, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "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.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "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, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/help-me": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", + "dev": true, + "license": "MIT" + }, + "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" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "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, + "license": "ISC", + "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, + "license": "ISC" + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-retry-allowed": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz", + "integrity": "sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "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==", + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "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, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/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, + "license": "MIT", + "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/lazystream/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, + "license": "MIT" + }, + "node_modules/lazystream/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, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "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, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.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, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", + "dev": true, + "license": "MIT" + }, + "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==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "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, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.19", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", + "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "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, + "license": "MIT", + "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, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/meow": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", + "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "license": "ISC", + "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, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-releases": { + "version": "2.0.21", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.21.tgz", + "integrity": "sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "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, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pino": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-8.21.0.tgz", + "integrity": "sha512-ip4qdzjkAyDDZklUaZkcRFb2iA118H9SgRh8yzTkSQK8HilsOJF7rSY8HoW5+I0M46AZgX/pxbprf2vvzQCE0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^1.2.0", + "pino-std-serializers": "^6.0.0", + "process-warning": "^3.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^3.7.0", + "thread-stream": "^2.6.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz", + "integrity": "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^4.0.0", + "split2": "^4.0.0" + } + }, + "node_modules/pino-pretty": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-10.3.1.tgz", + "integrity": "sha512-az8JbIYeN/1iLj2t0jR9DV48/LQ3RC6hZPpapKPkb84Q+yTidMCpgWxIT3N0flnBDilyBQ1luWNpOeJptjdp/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "colorette": "^2.0.7", + "dateformat": "^4.6.3", + "fast-copy": "^3.0.0", + "fast-safe-stringify": "^2.1.1", + "help-me": "^5.0.0", + "joycon": "^3.1.1", + "minimist": "^1.2.6", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^1.0.0", + "pump": "^3.0.0", + "readable-stream": "^4.0.0", + "secure-json-parse": "^2.4.0", + "sonic-boom": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "bin": { + "pino-pretty": "bin.js" + } + }, + "node_modules/pino-std-serializers": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz", + "integrity": "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==", + "dev": true, + "license": "MIT" + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "node_modules/process-warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", + "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true, + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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" + } + ], + "license": "MIT" + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "dev": true, + "license": "MIT" + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, + "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, + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", + "dev": true, + "license": "MIT", + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/regexpu-core": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.2", + "regjsgen": "^0.8.0", + "regjsparser": "^0.13.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.2.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", + "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/require-module": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/require-module/-/require-module-0.1.0.tgz", + "integrity": "sha512-fbr7gXnwot8k98dOUIq9KA4tvEot+CNMg1GR6j1v+7gI3aECMeyxmw2Ux0RWecPR6GfLqktVJ84GlTXoFlS2Cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "~0.6.1" + } + }, + "node_modules/require-module/node_modules/resolve": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.6.3.tgz", + "integrity": "sha512-UHBY3viPlJKf85YijDUcikKX6tmF4SokIDp518ZDVT92JNDcG5uKIthaT/owt3Sar0lwtOafsQuwrg22/v2Dwg==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "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, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.3.tgz", + "integrity": "sha512-RIDh866U8agLgiIcdpB+COKnlCreHJLfIhWC3LVflku5YHfpnsIKigRZeFfMfCc4dVcqNVfQQ5gO/afOck064A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.52.3", + "@rollup/rollup-android-arm64": "4.52.3", + "@rollup/rollup-darwin-arm64": "4.52.3", + "@rollup/rollup-darwin-x64": "4.52.3", + "@rollup/rollup-freebsd-arm64": "4.52.3", + "@rollup/rollup-freebsd-x64": "4.52.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.3", + "@rollup/rollup-linux-arm-musleabihf": "4.52.3", + "@rollup/rollup-linux-arm64-gnu": "4.52.3", + "@rollup/rollup-linux-arm64-musl": "4.52.3", + "@rollup/rollup-linux-loong64-gnu": "4.52.3", + "@rollup/rollup-linux-ppc64-gnu": "4.52.3", + "@rollup/rollup-linux-riscv64-gnu": "4.52.3", + "@rollup/rollup-linux-riscv64-musl": "4.52.3", + "@rollup/rollup-linux-s390x-gnu": "4.52.3", + "@rollup/rollup-linux-x64-gnu": "4.52.3", + "@rollup/rollup-linux-x64-musl": "4.52.3", + "@rollup/rollup-openharmony-arm64": "4.52.3", + "@rollup/rollup-win32-arm64-msvc": "4.52.3", + "@rollup/rollup-win32-ia32-msvc": "4.52.3", + "@rollup/rollup-win32-x64-gnu": "4.52.3", + "@rollup/rollup-win32-x64-msvc": "4.52.3", + "fsevents": "~2.3.2" + } + }, + "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" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "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" + } + ], + "license": "MIT" + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/secure-json-parse": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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, + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/sonic-boom": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.1.tgz", + "integrity": "sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "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, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "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, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "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, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "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, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/systemjs": { + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/systemjs/-/systemjs-6.15.1.tgz", + "integrity": "sha512-Nk8c4lXvMB98MtbmjX7JwJRgJOL8fluecYCfCeYBznwmpOs8Bf15hLM6z4z71EDAhQVrQrI+wt1aLWSXZq+hXA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar-stream/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, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/terser": { + "version": "5.44.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz", + "integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "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, + "license": "MIT" + }, + "node_modules/thread-stream": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.7.0.tgz", + "integrity": "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + } + }, + "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, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ts-api-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "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, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "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, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "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.2.1", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.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, + "license": "BSD-2-Clause", + "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, + "license": "MIT" + }, + "node_modules/vite": { + "version": "5.4.20", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.20.tgz", + "integrity": "sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite/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, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/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, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/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, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/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, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/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, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/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, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/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, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/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, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/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, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/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, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/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, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/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, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/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, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/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, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/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, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/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, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/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, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/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, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/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, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/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, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/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, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/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, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/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, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/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, + "license": "MIT", + "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/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.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, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "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, + "license": "MIT", + "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, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "dev": true, + "license": "MIT", + "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/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zip-a-folder": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/zip-a-folder/-/zip-a-folder-0.0.12.tgz", + "integrity": "sha512-wZGiWgp3z2TocBlzx3S5tsLgPbT39qG2uIZmn2MhYLVjhKIr2nMhg7i4iPDL4W3XvMDaOEEVU5ZB0Y/Pt6BLvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "archiver": "^3.1.1" + } + }, + "node_modules/zip-stream": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-2.1.3.tgz", + "integrity": "sha512-EkXc2JGcKhO5N5aZ7TmuNo45budRaFGHOmz24wtJR7znbNqDPmdZtUauKX6et8KAVseAMBOyWJqEpXcHTBsh7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "archiver-utils": "^2.1.0", + "compress-commons": "^2.1.1", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/zip-stream/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, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + } + } +} diff --git a/GPTutor-Frontend-v2/package.json b/GPTutor-Frontend-v2/package.json new file mode 100644 index 00000000..161120bc --- /dev/null +++ b/GPTutor-Frontend-v2/package.json @@ -0,0 +1,41 @@ +{ + "name": "gptutor-frontend-v2", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "start": "vite", + "build": "tsc && vite build", + "lint": "eslint --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview", + "tunnel": "vk-tunnel --http-protocol=http --host=localhost --port=5173", + "deploy": "vite build && vk-miniapps-deploy" + }, + "dependencies": { + "@vkontakte/icons": "^3.1.1", + "@vkontakte/vk-bridge": "^2.13.0", + "@vkontakte/vk-bridge-react": "^1.0.1", + "@vkontakte/vk-mini-apps-router": "^1.7.6", + "@vkontakte/vkui": "^7.0.0", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@types/react": "^18.2.43", + "@types/react-dom": "^18.2.17", + "@typescript-eslint/eslint-plugin": "^6.14.0", + "@typescript-eslint/parser": "^6.14.0", + "@vitejs/plugin-legacy": "^5.3.1", + "@vitejs/plugin-react": "^4.2.1", + "@vkontakte/vk-miniapps-deploy": "^0.1.6", + "@vkontakte/vk-tunnel": "^0.2.4", + "eruda": "^3.0.1", + "esbuild": "~0.20.0", + "eslint": "^8.55.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.5", + "terser": "^5.4.0", + "typescript": "^5.2.2", + "vite": "^5.0.8" + } +} diff --git a/GPTutor-Frontend-v2/public/logo.svg b/GPTutor-Frontend-v2/public/logo.svg new file mode 100644 index 00000000..40d5b0e4 --- /dev/null +++ b/GPTutor-Frontend-v2/public/logo.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/GPTutor-Frontend-v2/src/App.tsx b/GPTutor-Frontend-v2/src/App.tsx new file mode 100644 index 00000000..dee40999 --- /dev/null +++ b/GPTutor-Frontend-v2/src/App.tsx @@ -0,0 +1,32 @@ +import { ReactNode, useEffect, useState } from "react"; +import { ScreenSpinner, SplitCol, SplitLayout, View } from "@vkontakte/vkui"; +import { useActiveVkuiLocation } from "@vkontakte/vk-mini-apps-router"; + +import { Home, Persik } from "./panels"; +import { DEFAULT_VIEW_PANELS } from "./routes.ts"; + +export const App = () => { + const { panel: activePanel = DEFAULT_VIEW_PANELS.HOME } = + useActiveVkuiLocation(); + const [popout, setPopout] = useState(); + + useEffect(() => { + async function fetchData() { + // const user = await bridge.send("VKWebAppGetUserInfo"); + setPopout(null); + } + fetchData(); + }, []); + + return ( + + + + + + + + {popout} + + ); +}; diff --git a/GPTutor-Frontend-v2/src/AppConfig.tsx b/GPTutor-Frontend-v2/src/AppConfig.tsx new file mode 100644 index 00000000..f999f392 --- /dev/null +++ b/GPTutor-Frontend-v2/src/AppConfig.tsx @@ -0,0 +1,41 @@ +import vkBridge, { + parseURLSearchParamsForGetLaunchParams, +} from "@vkontakte/vk-bridge"; +import { + useAdaptivity, + useAppearance, + useInsets, +} from "@vkontakte/vk-bridge-react"; +import { AdaptivityProvider, ConfigProvider, AppRoot } from "@vkontakte/vkui"; +import { RouterProvider } from "@vkontakte/vk-mini-apps-router"; +import "@vkontakte/vkui/dist/vkui.css"; + +import { transformVKBridgeAdaptivity } from "./utils"; +import { router } from "./routes.ts"; +import { App } from "./App.tsx"; + +export const AppConfig = () => { + const vkBridgeAppearance = useAppearance() || undefined; + const vkBridgeInsets = useInsets() || undefined; + const adaptivity = transformVKBridgeAdaptivity(useAdaptivity()); + const { vk_platform } = parseURLSearchParamsForGetLaunchParams( + window.location.search + ); + + return ( + + + + + + + + + + ); +}; diff --git a/GPTutor-Frontend-v2/src/assets/persik.png b/GPTutor-Frontend-v2/src/assets/persik.png new file mode 100644 index 0000000000000000000000000000000000000000..426fcd707fafa471224c4db574f31549ed0df901 GIT binary patch literal 11033 zcmYj12{hDE_rKrF7{l0i*~S{O?~05i`x-^ok)4XN7tL?%BD+G$zC}osP)1}4SyFb! zPWB~h`1;Ow{^$JPx#zsQynEhz=iYbUJ@?#LQ)3-!$_tbL08s1cYF!5a*gq5opy2C5qO?$J=@VdvxHv66$&o+tB-N8jVu-`pI}GTZLU zo65BrN!8itdj2CycDB%Fw#cj{O0D>gbOZj%c#iRAja7xOT%0*yj;r{)V5O8>Lf=!g z2j4!a47-`@t)5~lRuXL3T?+k~X~A4^i5DREiMH`?k-{S~kJr$3ALdym;aL(=_HD5{tIO`3Ug#5jZ*ujr zo;)Y%^k>*dY1;E~rIe}hNf-PRq62fNb3poOj(qE;MW{P!s^&cBv4lcs{$bY{ep>NY zabNtan)7#ETR9+UbYApCP4@3ZrKH&K+Dr0)T_viB58e;?lAT_sG@J{5_`7n*&w@?XRa*ha0M1>KUZEZz>-`p>0;G-ut{Nc^4tV%09OROwE3eAVko#T|tZO+vt*xdN zGXgA|`s1|fLk}Fd_{ebcmS%uZ6N6UGSi?yPfVp57hmu|AoU+p5o2WlQ|6D{t6iKu} z9sYdu_r_0iL>K@xM8Ok#Teafu0ls*i)fKFsm3^Tb@gm^djg5?j37~*wq7>K9`U>xW zQs5R%O1M>x$JnU|z^~{a2!#nS%PQ_!(!WIsDHbfIbvK#OFP?#SZ&3 zP7GLzfX+!{n7~Sv0DfrU=FHhw7>=B+TC?7ha^);V@KVDpRZzP`_l-w|5LZn*VGUqJ z{5u?a<%|itVgpRgpx!zjJa_I5X9u-8UEHTnMW7To?(6+*@9EQBGNL$%yCkFX0-JYG`25vzucm;wARbUhiRoklf@QRzb`_uZU!zhh z#3>u_5@fD41ls;oCiyI0h3ti?m8(}Fm{K=g5JWJuEO;9A%)SJgYQf^QfO(Tv5a&sz z=*Ge04c!D^gu{Ao3J1&i0mV0c6awPI&+cRrc2N+!PgwFT)&WCp^FW=;w=&CCP zx?={|UrU?s$hF642t(%LI1Of7w?zN-5k-v=SVC#5#nO?%<=`UfkI##O1XCtd%QP4y zqm#)$A}!*C;Uv*JI#mkJNVx)To6{x9I1@AEAaHpITN_5tOwn;q(FMsw_?^>EaYL^b zI+cea8Y*_)Bv5Ku6F-9pi}q_4VJx{)5cP9nXBF*)EJXjD_~>G%80r2+c!L1?@TGa~ zORDATVx(aQiD%9G!+=B^?DM&94022IQDC08A}SmV37D9S)KD&4Z)iG?>s1sg`hM%M z=v=2BwxR>;IZ9ZvhOKQX78 z3|}CCz`*y)8X3^p3v<`@z26Y|;GUH&yKaM|z~aZr6_^OOx(DAI)kD=$M~sWp`A!vU zp<&7U7;gAXB8-z(bf%=I2WJRNvF86-jJ zYamtp_Qu!+rv|~?uwp=J>GPX`d>fdkl>*?)J!WmkCx|%~O(Li#-hBg3GML(pL=h0- zV-J}ms0P!a)E^$r)8CV{AR*PdKc(r=?vItGY01QLGEqg`ps$U$)+#3G16B{ZMVlz; z90z?+kPDlJ?)OzOX6X^HptaQzwglUX0P`?CY+sn86oqSkYKcFmR4tA(jQ}41 zN?LH#SXRn)Y{AykTF!h`T^P4=NrSIzo@1*JdhZLtVXGv-?9#rF{!H8#4=5TrKZ z>*7^v&32|3Q|bxUKT?7w&@Edc${r3iuiTuTpk_=e9T0RF+fYoA6}q^O*_ zz9SUIR&NAHm{tnt%KJEuw8~|ZeFGc-zj=4q*vorWYHT-Q5K#ep9elOp9ew{ks}2l| zva|is=uDAh(jrH?7ok@zF$PI?l$~eMJ6+h4APXfGpxg)+69wDn+;G4CrPmrtCT2W` zN`oGz)CcY#=~#U$l=I0lNG#8(K$$_b&&4qhQ?7%79;=^$Spo6b?Y}X9Iz*VUXIGPc zAQ*bsH=KAXpvwoUgSXLAS$idM;}vTA?67QoNvNi`JS1rQj=;#XhuG~G3itZwDEr&b z2R~M{xek1_du9RcAwZLKyQ?+Sm>$0Pn8~-r=`3>&Kyr_jkNB4MyzjwNr4?^5(aS?}Egb{N8D{wo z9Tb+Q3x0BZd7Gu5)|}WF_mwiV2_BZ%vou`n z;VHGMvkZ<4Eu_~k8|wg~KB`3EJf)ec-@K)WShpTeaCpoIC^Njz*xQQg*UL4LmWMT& zvV}yLX0vdIRhF4?3sYZztfeT1<{q?c&|HxiiPne(Bn6uVlISVuhT5qLaI0D1Oooy3 zY&8ucUML9u(EQh1pPUcZ-C7RPOmzjYK1)U~>`tNzV2R36P9L*n9a{s)od$17nM53g zq*()z9UjkK>?r6BDgJno<&;53-MW~T^OVd>=>b@_CptPtz#0VA69A$BQ zJQ;m?OJSVh!Sw=m-U0x}fLm<(RC4~hiaSYE_%lmndtU}J@W6t&x?Gg4|>#v1lQdS@q zT+R0rg<>Q@HFK*%QSzPz^$6hEh^n-jaWY_X^e;1!+rD78mW7Jcd*a%1@s=*jQ%X!O zz3|IoUFgx1!|pF-fOy_2Utf)Kq`GGq=>TI0Fa_T=<-+7}gIabBU0q>h8|VrafaGM2 z2>Plz;Kgs zG!RHeeSY`@L*v#Vo%>Mxd4z#DQT1%gBnC*xMGHvcG=->PDohH0=S;#8Y^D+7Qw!HI zQ1uKC{(=Azy0Eroea2D9vm1@Sjc|tmxMy`oVj(LjvVSJWi_H%KIYO z4!Q!1#=C}BkU1KM|5BS!eg(?sHg$dsA+lR4pdgBEa(yRJmJipH^l9D0hIugkA`$O`1wkB#%p7gQ8 z;ENh110dcm7qgKJektKlL+U$V(iD|5-PB>bc*an%4LRMqTjMV19B=6}-Voh5AXt}0 zyb~DaK_(r)i$W|ZD)C*v3|CNlu80cZy$-nNCEokDe?qT=q+R?GXQ@39?eKTUa)pk> zB@pjbkfdNn&cGbBvV>g z+O_FRRX~LZ-2{AmI6@7J)t%5E-ac^SFj@Bd7-! z(;>e&mi3Xhc)yln?@XPA49|+ScV}EaeIf@=lj)+*_x|cZ@kYev(JNJCKmEBW&ug_J z@-7!sYwp-KK76>ju%&h?(ug+YiFy7LEyYL8LxO-~I z*CGUfnQvlbE!#8>OqF{wVMmENO|(L2^_i`%zuk=c5FZ2`dY&y%J;Kssv7DLsU~O(G zIZ&4tS7}DWmH`x!6QxbX|1l^dbO=952#h!245mN`OcMqT-OdG4u=@Wt{A zEP@x9IqUq}QQph~sp}w2Z-c$8)8dd=#E2wZLK1PH1PoI4Ot=PGWR|+$xT~hjc_D#JF0oqU4Zq@7q!Z|k zntO z4HKBS8Ow+cYWzEw;kL#{!n266Y*E~#-cc!eLj3OB^5sj&68o>o0u^3?e*FLp#qU*z z7&5K#T&bVU8O~>JFb1;05NlRg;W6t7`VjBqM~j!&ua}uVLXmB_hwAjd)@7JiUGfqq z=}P9gR!1pqt59S;0TOxxB_IWzTILx3Tj)R8{3_(4`khfC6@$+b+k<-H#$a5Dv*%hf za~cNN4ZDtY20vcQwM@R+ZGJ4Sgl&i3=lRvYdxu;2E|E(D;26@{dZ?1E%K>TR${N$gu(doK8$<>*qrZs) znwXfsje-K`$MhtG!kKyx#Fwl<+=L~G_F~{q>iO?N=VZ_{Vni|gpMovG#ALerhI)kd zz;*d2yoEe#6AV=dTRvA_lkR7=r;JyE_-3_=!80aEmXt`SCf^%F4uu60o_nE*=kjRb zyv5<`{Q@LuItifa+Y}75-(*dBA?gZwdkKN0H*N!H*>11+bQ%T_ntksV-l78L=5W>Q z@6jQ$UWl#3BV*qTAY7FqTvdtoNfn}AN(Eelhu6=Vu~ldo5e5{t=G@-(bG8%nE;??V zsL?*rCuYu2V8O&nwep#FQks|$zWE-u-CTA?7i4cF14YaFxlT!&Hze zkosQHaSKyV7el(+$epXU>nM-C37ew&`su3-o&FH=?2ssI%Npb&{C=FQ>*lj-jWrBg z#*eUJ>x;l{dRqNPw?3A8gb!#*{wctA$}4J%;k!@ZzJ)cWQ-VG5t0~ryQ#}e|LIj8x zegYokjyTxx@tNF&Y4fg!rA&65}kr7kb~rJ>f1I z(EoAcIKcqQrhOzWhhBwA<#v2c7K{3PF--*LXafw=zhss_MTK9Sp$hY0dCyL)b+>2h zx?M`k3uyi`aVL6i_L*4JLpqogBKJ5AH2r!BZpXu-*+GZ~sK6ddeyrhiTpmuf>1#j# zBQX9OBk&sG7ve+MK?>6oAx9vVp+D)XspJ&k>bMOXajQt^_;>fuPPiywu?Y#q!1;N; z;DX^8(6o;+byrk-GTH_58)pW$PrE@7?FOH1bM@HBo4l}+Sn$fJPXE3%0Cu)Y%zpH&du(Vpw+7I35Mn?Zc zW{*+e(w@RUo53sL|g!6CsR}hp66|k8yl|g+x3+Hm4b3bN(vgw!U3?i*+q+BN6 z=A6gl zBzoj4B}$JuJatD{Fh0VUr;Ex!U^HwPxj8(eJvUU^E4>dAw7I-*D| zTlIe8Dr>`&Ob}ev=!h~216@J+j3ViNATH8iZdjLZYyabszHS8#+*@It<{X2g_si7l z(qRpb6AX^^?j=2-xqlK!wHIiC?6wf37!yT4*o1XJD|gvpv(a+CJ9+sSgpWtPSgoc| zwN`4@*PX7o{q$L_6wD*q<*Vo($IOHU4(PDqsI>3c{f&USWYp6W81~ol>vXtQY0Iyi z*RP{7K*J3n%@nVI@qm0-}^p9G!$3EWlVTf)-8ZoJAvF_>J2k zYUDf(TIDSPJeR!4F;JxAmf!8qdD(721bX6K0w9&jL`SX6QPcBMWPW#aRX${C|7h)N zFiO{%aCan)e)FuR(z)dYC;I9UDx;;PZJjg2hd_NolY97A-}Y?+tknxf;|)4~ICrpk zF0FcEmm5FnEvE%c2$3?+kcAKC0cmkBu#oX_>p;3AuoDs_TQUEe|koT2ZJ|h$+`qp!$O~tBBGRbbq7x z^IS$glp$H`=WCng5n?&iKXOtKV@oC-EYC=49A(>SD=cFSB(q9Dm<~hbuIwY?bL;~e z7!%F6mJf`fgA_F8x9hEE+MxO40ad)`mjz;DQNW*&YptYT^gAy8$RtUN_r`C3U6De& zGh3H3$+=!&$p8R5&<18$c1I~ePj&S;D9nH7y)LA@d6RiU>0g*hQ$RZSYIl<{Y+jV6 z5(Uux#D}fkCp~)%$@5wrO5j89Yvc`f$;U!wuL@-I47C_Iv7bpE_<@G+Z>1gXkKQpN zsDKigXq;UHcWiYcTX@OyR7}`KSV>XuYV5*Dj5xSK_t63P!4GVKGs9?MB>u00na8g9PEEMXnOqP-J<;fEr)n{@Fk zjUU2WNE?6H-f^g((JI7$nBoM#r$^n6P)&?LJu6vs(`mcCLkyJU$cY#k|Bect=O<>} zGRbD*)-!86dQv|jhK8F=AmYRTnFPg6%F`M-nBO`KZ+si^>G0$2VMrm$=(uW!Xb~9W zzWatANCaYF9S5w1<+8i3FRTo8THOxgOi*KWvSe2ufBgjiS386t=a|ce-ydVfIXb%4 zPuU40Wyylei*r0xk0+h+L7Oo^U;sUE5t@EFsxyAIN%_HNrL*lcQ_f%Q410(95|8}1 zm%{+x$iffgFRvN^+*h6oQY|NvM-`DT;RRquQKc8CuSI zBuG`CZPJC*`TmV?f5wbXP>sCKj{27Egm?V~6+Y(k@UFp5r|(y1S>v}5q=DI25vd?Z z)DOEG0o1FC$`~xw+I^Z916{L}y)*m=$z&Fn$q+c7Agw1#BkuAsN1X#tltUd9^dXyz zKi&HhF`lBZi~|wB>T|0)>y&-W&rpV5x&TqClTXI5qZ%$= zPpVscV0$WFDkP=$EHJ{Q5|!HvxPA;J7$&Ml7Sh{_;gfn+vTyoHB#!X+tAcB+apWGc zPFp^6*Kzf2GDUu9)eO2v;m-zxc#Dr(fv+{z27%EMX`=rQJX>5T!v)`NHR^N zs?)5&+ERqI3+zY3EEGx?4a#UZhtq*WPd!QL?gSFsN7o^>jdeOfto1GLEpdAaKP>=P zjx~)aAKWrRgQL4gNOx3BngJL>X*!ev5bcwNMPk1YWl4x;JRvl*AP%Ff5!2`y3FTO)kkhWSJuS5+6lJ;+Mgg7n%(%ZyqsW zx3lhJp_QX)*=2`27!7Er_i>f{NL=e6r(?k65cJz ze%D&|V$7Yx)25sY8-SP3pCf>Mn`4>?z&NUjlg6$Ij&^PTW~kf)pwdym9pyd{mYtUX zV97Ztr2!Pwq=`JeTnJ>!fKd$y_m!!q%BgUTP2ww8>EB(Ul%xnC@(n-cMku1^E-K0E z@iZg32qXm3h*Ko-ozEw~)`(hx3|oyW*&~W8hHw+~Bqr7{(Tl{ZUZT|z>f9hYUY^3# z2a%y9jK~cIsrKs|zNK@68SH}g!=-kC{HzF4y6_(j0BU;$luWoC6&gawAHx-zP#!f{ zN-5|$pGyZQM$6!C)S(y=XP`T0(#jvdA*EEU=2+QPkPgnLcF z?aGZCD4;&^6H{jvY#4$1*yPcEeoBL?Zq#<_Twgm@A2HojpX0M>YjrKUdWWKe0$PIV zhvGq{rz|O;3|r5ch$@maNN=P< z^k;_VD<#7CvCVwE!iGOoN*H{UNt}w|^%Y1(4xL%`Hkf$ZSV#}1)c`z32Mryw#LJH2;JEE{1SlxFE+xtffS^LSXU_$*L)hRt5#1B$43(kC3t&er@-+eEEn^r}J!kd1U|4^#X`3P6d-C8uz&l9-><_e_9njDA zRmQEo0@BTMqb2F_fl#^8F#?iUX-oZvbz0^vPe@XT9cp4@9I55eo)h1Ay7l!<$XuQ|7m9G6lZdo3qFzJe?)Ru1 zPtak^#wM@ae+GwrNyqxd`dY&;9?J3k_4+~q^^p@<597U3;Mxf2l;tw_=b`ZptK9^w)CeE#J)m z0{;mvY1&$Tdo#}2Plpt;9(90~yyvHw`%M8^hD%fSK+3f=_5}M^ODmRsH9c*$z$2S~ zOQPSWmNjmma9qW*iEj{gm%oFIgvRfTAH5Bon-v&t!1!LyP+jlw`%>F?G*B7*;NxSm z#coyO5X=UwhR%r$NQ1BobH9IvZ55~46b`PDn3tV@lKcMraddx-v}UHK>$B!41Cg@r38cel4UOQMTb7A_i=JqfC2FY z`{cHL1U4Nvd5zg5#L(Y?@|%F%Hu0Fe3O45{WdaL-^(CAdyj>x_b!o6lcxS??anN;x z2UL+U%hj#86t4r56>i9F-}H}v?2QpXWC@%;`FknE8u_RySw`hnDswufqgN`#MCy#L zmh(b5BR~&pg|w91c-Zt_>Z{ugI3;VWy}-Q&fbY7nK4C^+>rSvhE8_{V^Y=Wt!8Q50 z2e$}k4moG+jK^?l zK^i0OFK16Pa;g@C0N_)LO2eSR!-`7yAKeJ$e&5A!G--Mo*MjXfwttvZp`-aR0O{`R zXEScb1E9@=9bUP;m(SNfhQPsxdoM1AwK@PdrE{gmd||v?rToFa$`p|l>IFkL}a}E z;a{@9M0*_euzg=MamWQAT-hjFi&Xc|qGo`rw)J@Zeh_v80_4CI@^Q}B)2yyLJEJ(m zjI|*hBqb)XuY4YlJRpGXvV*jMgCX!#@4JX3d}q6;w9gp|`LlV-=)GtIgE3!31XSEZxv1G{?$XU*StG06%zg zcje>|Mk5U+BY91t(a?dU?oRj3^AI6&Yp70AfHN!f3Qm$qf^6+>9MhVWU!UsZ$!*~R zlvS##lTi@ugS|qv2mVQ98G5tx(WtPJC!|?+? zB2%yjd`c1U->TZE zv#zh)wvjIMm*2F|nzAfa&GY*DX*4L6+}!>m>gZ=n&soR!P>e2Bm?>~76c8SC-hFQ~ zlr@ugG+43PGUMkV&C-qCueZ|FsnEg(f@jvR1h#04?!0h_hK+{bCDK>_UY@8K64izB%V*f~J-P0P#EFG@ z(==qYs^7Wxj)s%DWot7`(b%qaMoHnq)KbNMV0z|C%N7r6kKWb8``K); + +if (import.meta.env.MODE === 'development') { + import('./eruda.ts'); +} diff --git a/GPTutor-Frontend-v2/src/panels/Home.tsx b/GPTutor-Frontend-v2/src/panels/Home.tsx new file mode 100644 index 00000000..4d9ffd4e --- /dev/null +++ b/GPTutor-Frontend-v2/src/panels/Home.tsx @@ -0,0 +1,298 @@ +import { FC } from "react"; +import { + Button, + Card, + ContentCard, + Counter, + DisplayTitle, + Div, + Flex, + Headline, + Link, + NavIdProps, + Panel, + PanelHeader, + Separator, + Spacing, + WriteBar, + WriteBarIcon, +} from "@vkontakte/vkui"; +import { + Icon12ArrowshapeRight, + Icon16LinkOutline, + Icon24BracketsSlashOutline, + Icon24DocumentTextOutline, + Icon28KeyOutline, + Icon28KeySquareOutline, + Icon28MoneySendOutline, + Icon28PaymentCardAddOutline, +} from "@vkontakte/icons"; + +export interface HomeProps extends NavIdProps {} + +export const Home: FC = ({ id }) => { + return ( + + LLM API +
+ +
+ + Единый API интерфейс нейросетей
в одном сервисе! +
+ + + Без ВПН и зарубежных карт! + +
+ + {}} + after={ + <> + + + } + placeholder="Что ты умеешь?" + /> + +
+ {}} + src="https://storage.yandexcloud.net/gptutor-bucket/Slide%204_3%20-%201%20(3).png" + title={Одно API для всех моделей!} + description={ + + Доступ ко всем основным моделям осуществляется через единый + интерфейс. OpenAI SDK работает "из коробки". + + } + caption={ + } + > + Посмотреть модели + + } + maxHeight={200} + /> + + +
+ +
+ + + 1 + + Пополни баланс + + + + + + + + 100₽ Бесплатно! + + + + +
+
+ +
+
+ + + 2 + + Получи API-ключ + + + + + + sk - •••••••••••••••••• + + + +
+
+ +
+
+ + + 3 + + Используй API + + + + + + +
+ +
+
+ +
+
+ +
+
+
+ + +
+
+
+
+
+
+ ); +}; diff --git a/GPTutor-Frontend-v2/src/panels/Persik.tsx b/GPTutor-Frontend-v2/src/panels/Persik.tsx new file mode 100644 index 00000000..5fb6a7f0 --- /dev/null +++ b/GPTutor-Frontend-v2/src/panels/Persik.tsx @@ -0,0 +1,19 @@ +import { FC } from 'react'; +import { NavIdProps, Panel, PanelHeader, PanelHeaderBack, Placeholder } from '@vkontakte/vkui'; +import { useRouteNavigator } from '@vkontakte/vk-mini-apps-router'; +import PersikImage from '../assets/persik.png'; + +export const Persik: FC = ({ id }) => { + const routeNavigator = useRouteNavigator(); + + return ( + + routeNavigator.back()} />}> + Persik + + + Persik The Cat + + + ); +}; diff --git a/GPTutor-Frontend-v2/src/panels/index.ts b/GPTutor-Frontend-v2/src/panels/index.ts new file mode 100644 index 00000000..7fd66436 --- /dev/null +++ b/GPTutor-Frontend-v2/src/panels/index.ts @@ -0,0 +1,4 @@ +export { Persik } from "./Persik.tsx"; +export { Home } from "./Home.tsx"; + +export type { HomeProps } from "./Home.tsx"; diff --git a/GPTutor-Frontend-v2/src/routes.ts b/GPTutor-Frontend-v2/src/routes.ts new file mode 100644 index 00000000..2d615861 --- /dev/null +++ b/GPTutor-Frontend-v2/src/routes.ts @@ -0,0 +1,27 @@ +import { + createHashRouter, + createPanel, + createRoot, + createView, + RoutesConfig, +} from '@vkontakte/vk-mini-apps-router'; + +export const DEFAULT_ROOT = 'default_root'; + +export const DEFAULT_VIEW = 'default_view'; + +export const DEFAULT_VIEW_PANELS = { + HOME: 'home', + PERSIK: 'persik', +} as const; + +export const routes = RoutesConfig.create([ + createRoot(DEFAULT_ROOT, [ + createView(DEFAULT_VIEW, [ + createPanel(DEFAULT_VIEW_PANELS.HOME, '/', []), + createPanel(DEFAULT_VIEW_PANELS.PERSIK, `/${DEFAULT_VIEW_PANELS.PERSIK}`, []), + ]), + ]), +]); + +export const router = createHashRouter(routes.getRoutes()); diff --git a/GPTutor-Frontend-v2/src/utils/index.ts b/GPTutor-Frontend-v2/src/utils/index.ts new file mode 100644 index 00000000..23479a90 --- /dev/null +++ b/GPTutor-Frontend-v2/src/utils/index.ts @@ -0,0 +1 @@ +export { transformVKBridgeAdaptivity } from "./transformVKBridgeAdaptivity.ts"; diff --git a/GPTutor-Frontend-v2/src/utils/transformVKBridgeAdaptivity.ts b/GPTutor-Frontend-v2/src/utils/transformVKBridgeAdaptivity.ts new file mode 100644 index 00000000..194ed2d1 --- /dev/null +++ b/GPTutor-Frontend-v2/src/utils/transformVKBridgeAdaptivity.ts @@ -0,0 +1,31 @@ +import { + type AdaptivityProps, + getViewWidthByViewportWidth, + getViewHeightByViewportHeight, + ViewWidth, + SizeType, +} from '@vkontakte/vkui'; +import type { UseAdaptivity } from '@vkontakte/vk-bridge-react'; + +export const transformVKBridgeAdaptivity = ({ + type, + viewportWidth, + viewportHeight, +}: UseAdaptivity): AdaptivityProps => { + switch (type) { + case 'adaptive': + return { + viewWidth: getViewWidthByViewportWidth(viewportWidth), + viewHeight: getViewHeightByViewportHeight(viewportHeight), + }; + case 'force_mobile': + case 'force_mobile_compact': + return { + viewWidth: ViewWidth.MOBILE, + sizeX: SizeType.COMPACT, + sizeY: type === 'force_mobile_compact' ? SizeType.COMPACT : SizeType.REGULAR, + }; + default: + return {}; + } +}; diff --git a/GPTutor-Frontend-v2/src/vite-env.d.ts b/GPTutor-Frontend-v2/src/vite-env.d.ts new file mode 100644 index 00000000..11f02fe2 --- /dev/null +++ b/GPTutor-Frontend-v2/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/GPTutor-Frontend-v2/tsconfig.json b/GPTutor-Frontend-v2/tsconfig.json new file mode 100644 index 00000000..d05b11b5 --- /dev/null +++ b/GPTutor-Frontend-v2/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": [ + "src" + ], + "references": [{ "path": "./tsconfig.node.json"}] +} diff --git a/GPTutor-Frontend-v2/tsconfig.node.json b/GPTutor-Frontend-v2/tsconfig.node.json new file mode 100644 index 00000000..b5a34318 --- /dev/null +++ b/GPTutor-Frontend-v2/tsconfig.node.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": [ + "vite.config.ts" + ] +} diff --git a/GPTutor-Frontend-v2/vite.config.ts b/GPTutor-Frontend-v2/vite.config.ts new file mode 100644 index 00000000..816e9180 --- /dev/null +++ b/GPTutor-Frontend-v2/vite.config.ts @@ -0,0 +1,38 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; +import legacy from '@vitejs/plugin-legacy'; + +function handleModuleDirectivesPlugin() { + return { + name: 'handle-module-directives-plugin', + transform(code, id) { + if (id.includes('@vkontakte/icons')) { + code = code.replace(/"use-client";?/g, ''); + } + return { code }; + }, + }; +} + +/** + * Some chunks may be large. + * This will not affect the loading speed of the site. + * We collect several versions of scripts that are applied depending on the browser version. + * This is done so that your code runs equally well on the site and in the odr. + * The details are here: https://dev.vk.com/mini-apps/development/on-demand-resources. + */ +export default defineConfig({ + base: './', + + plugins: [ + react(), + handleModuleDirectivesPlugin(), + legacy({ + targets: ['defaults', 'not IE 11'], + }), + ], + + build: { + outDir: 'build', + }, +}); diff --git a/GPTutor-Frontend-v2/vk-hosting-config.json b/GPTutor-Frontend-v2/vk-hosting-config.json new file mode 100644 index 00000000..7d39a211 --- /dev/null +++ b/GPTutor-Frontend-v2/vk-hosting-config.json @@ -0,0 +1,9 @@ +{ + "static_path": "build", + "app_id": 0, + "endpoints": { + "mobile": "index.html", + "mvk": "index.html", + "web": "index.html" + } +} diff --git a/GPTutor-Frontend/package-lock.json b/GPTutor-Frontend/package-lock.json index 7698fa9c..ada879fc 100644 --- a/GPTutor-Frontend/package-lock.json +++ b/GPTutor-Frontend/package-lock.json @@ -17,8 +17,8 @@ "@monaco-editor/react": "^4.5.1", "@telegram-apps/sdk": "^1.1.3", "@types/node": "^12.0.0", - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", + "@types/react": "^18.0.28", + "@types/react-dom": "^18.0.28", "@uiw/react-codemirror": "^4.21.7", "@vkontakte/icons": "2.98.0", "@vkontakte/vk-bridge": "^2.14.1", @@ -87,6 +87,7 @@ "version": "1.2.6", "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -2424,6 +2425,7 @@ }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", + "dev": true, "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.3.0" @@ -2437,6 +2439,7 @@ }, "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { "version": "3.4.0", + "dev": true, "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2449,6 +2452,7 @@ "version": "4.8.0", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.0.tgz", "integrity": "sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==", + "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } @@ -2457,6 +2461,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -2478,12 +2483,14 @@ "node_modules/@eslint/eslintrc/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==" + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "node_modules/@eslint/eslintrc/node_modules/globals": { "version": "13.21.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", + "dev": true, "dependencies": { "type-fest": "^0.20.2" }, @@ -2498,6 +2505,7 @@ "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" }, @@ -2509,6 +2517,7 @@ "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" }, @@ -2520,6 +2529,7 @@ "version": "8.48.0", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.48.0.tgz", "integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==", + "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -2583,6 +2593,7 @@ "version": "0.11.11", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", + "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", @@ -2594,6 +2605,7 @@ }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=12.22" @@ -2606,7 +2618,8 @@ "node_modules/@humanwhocodes/object-schema": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", @@ -3531,6 +3544,7 @@ }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -3542,6 +3556,7 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", + "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -3549,6 +3564,7 @@ }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -5599,6 +5615,7 @@ "version": "8.10.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -5638,6 +5655,7 @@ "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" } @@ -5728,6 +5746,7 @@ }, "node_modules/ajv": { "version": "6.12.6", + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -5819,6 +5838,7 @@ }, "node_modules/ansi-regex": { "version": "5.0.1", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -6988,6 +7008,7 @@ }, "node_modules/callsites": { "version": "3.1.0", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -7790,6 +7811,7 @@ }, "node_modules/cross-spawn": { "version": "7.0.3", + "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -8970,6 +8992,7 @@ }, "node_modules/deep-is": { "version": "0.1.4", + "dev": true, "license": "MIT" }, "node_modules/default-gateway": { @@ -9185,6 +9208,7 @@ }, "node_modules/doctrine": { "version": "3.0.0", + "dev": true, "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" @@ -9633,6 +9657,7 @@ "version": "8.48.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz", "integrity": "sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==", + "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -10598,10 +10623,12 @@ "node_modules/eslint/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==" + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "node_modules/eslint/node_modules/chalk": { "version": "4.1.2", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -10616,6 +10643,7 @@ }, "node_modules/eslint/node_modules/escape-string-regexp": { "version": "4.0.0", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -10628,6 +10656,7 @@ "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" @@ -10643,6 +10672,7 @@ "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" }, @@ -10652,6 +10682,7 @@ }, "node_modules/eslint/node_modules/globals": { "version": "13.20.0", + "dev": true, "license": "MIT", "dependencies": { "type-fest": "^0.20.2" @@ -10667,6 +10698,7 @@ "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" }, @@ -10676,6 +10708,7 @@ }, "node_modules/eslint/node_modules/type-fest": { "version": "0.20.2", + "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" @@ -10696,6 +10729,7 @@ "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", @@ -10712,6 +10746,7 @@ "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" }, @@ -10733,6 +10768,7 @@ }, "node_modules/esquery": { "version": "1.5.0", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" @@ -10743,6 +10779,7 @@ }, "node_modules/esrecurse": { "version": "4.3.0", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" @@ -10952,6 +10989,7 @@ }, "node_modules/fast-deep-equal": { "version": "3.1.3", + "dev": true, "license": "MIT" }, "node_modules/fast-glob": { @@ -10982,14 +11020,17 @@ }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", + "dev": true, "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", + "dev": true, "license": "MIT" }, "node_modules/fastq": { "version": "1.13.0", + "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -11021,6 +11062,7 @@ }, "node_modules/file-entry-cache": { "version": "6.0.1", + "dev": true, "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" @@ -11163,6 +11205,7 @@ }, "node_modules/find-up": { "version": "5.0.0", + "dev": true, "license": "MIT", "dependencies": { "locate-path": "^6.0.0", @@ -11177,6 +11220,7 @@ }, "node_modules/flat-cache": { "version": "3.0.4", + "dev": true, "license": "MIT", "dependencies": { "flatted": "^3.1.0", @@ -11188,6 +11232,7 @@ }, "node_modules/flatted": { "version": "3.2.7", + "dev": true, "license": "ISC" }, "node_modules/follow-redirects": { @@ -11564,6 +11609,7 @@ }, "node_modules/glob-parent": { "version": "6.0.2", + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -11702,7 +11748,8 @@ "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true }, "node_modules/graphlib": { "version": "2.1.8", @@ -12082,6 +12129,7 @@ "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, "engines": { "node": ">= 4" } @@ -12097,6 +12145,7 @@ }, "node_modules/import-fresh": { "version": "3.3.0", + "dev": true, "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -12111,6 +12160,7 @@ }, "node_modules/import-fresh/node_modules/resolve-from": { "version": "4.0.0", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -12389,6 +12439,7 @@ }, "node_modules/is-path-inside": { "version": "3.0.3", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -12539,6 +12590,7 @@ }, "node_modules/isexe": { "version": "2.0.0", + "dev": true, "license": "ISC" }, "node_modules/isobject": { @@ -14395,10 +14447,12 @@ }, "node_modules/json-schema-traverse": { "version": "0.4.1", + "dev": true, "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", + "dev": true, "license": "MIT" }, "node_modules/json5": { @@ -14527,6 +14581,7 @@ }, "node_modules/levn": { "version": "0.4.1", + "dev": true, "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", @@ -14580,6 +14635,7 @@ }, "node_modules/locate-path": { "version": "6.0.0", + "dev": true, "license": "MIT", "dependencies": { "p-locate": "^5.0.0" @@ -14630,6 +14686,7 @@ }, "node_modules/lodash.merge": { "version": "4.6.2", + "dev": true, "license": "MIT" }, "node_modules/lodash.sortby": { @@ -15088,12 +15145,6 @@ "resolved": "https://registry.npmjs.org/moment-mini/-/moment-mini-2.29.4.tgz", "integrity": "sha512-uhXpYwHFeiTbY9KSgPPRoo1nt8OxNVdMVoTBYHfSEKeRkIkwGpO+gERmhuhBtzfaeOyTkykSrm2+noJBgqt3Hg==" }, - "node_modules/monaco-editor": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.46.0.tgz", - "integrity": "sha512-ADwtLIIww+9FKybWscd7OCfm9odsFYHImBRI1v9AviGce55QY8raT+9ihH8jX/E/e6QVSGM+pKj4jSUSRmALNQ==", - "peer": true - }, "node_modules/ms": { "version": "2.1.2", "license": "MIT" @@ -15123,6 +15174,7 @@ }, "node_modules/natural-compare": { "version": "1.4.0", + "dev": true, "license": "MIT" }, "node_modules/natural-compare-lite": { @@ -15754,6 +15806,7 @@ "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, "dependencies": { "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", @@ -15768,6 +15821,7 @@ }, "node_modules/p-limit": { "version": "3.1.0", + "dev": true, "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" @@ -15781,6 +15835,7 @@ }, "node_modules/p-locate": { "version": "5.0.0", + "dev": true, "license": "MIT", "dependencies": { "p-limit": "^3.0.2" @@ -15823,6 +15878,7 @@ }, "node_modules/parent-module": { "version": "1.0.1", + "dev": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -15879,6 +15935,7 @@ }, "node_modules/path-exists": { "version": "4.0.0", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -15893,6 +15950,7 @@ }, "node_modules/path-key": { "version": "3.1.1", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -17258,6 +17316,7 @@ }, "node_modules/prelude-ls": { "version": "1.2.1", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8.0" @@ -17408,6 +17467,7 @@ }, "node_modules/punycode": { "version": "2.1.1", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -17465,6 +17525,7 @@ }, "node_modules/queue-microtask": { "version": "1.2.3", + "dev": true, "funding": [ { "type": "github", @@ -18299,6 +18360,7 @@ }, "node_modules/reusify": { "version": "1.0.4", + "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -18307,6 +18369,7 @@ }, "node_modules/rimraf": { "version": "3.0.2", + "dev": true, "license": "ISC", "dependencies": { "glob": "^7.1.3" @@ -18374,6 +18437,7 @@ }, "node_modules/run-parallel": { "version": "1.2.0", + "dev": true, "funding": [ { "type": "github", @@ -18700,6 +18764,7 @@ }, "node_modules/shebang-command": { "version": "2.0.0", + "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -18710,6 +18775,7 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -19194,6 +19260,7 @@ }, "node_modules/strip-ansi": { "version": "6.0.1", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -19228,6 +19295,7 @@ }, "node_modules/strip-json-comments": { "version": "3.1.1", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -19646,6 +19714,7 @@ }, "node_modules/text-table": { "version": "0.2.0", + "dev": true, "license": "MIT" }, "node_modules/throat": { @@ -19878,6 +19947,7 @@ }, "node_modules/type-check": { "version": "0.4.0", + "dev": true, "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" @@ -20072,6 +20142,7 @@ }, "node_modules/uri-js": { "version": "4.4.1", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" @@ -20662,6 +20733,7 @@ }, "node_modules/which": { "version": "2.0.2", + "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -21175,6 +21247,7 @@ }, "node_modules/yocto-queue": { "version": "0.1.0", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -21219,7 +21292,8 @@ "@aashutoshrathi/word-wrap": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==" + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true }, "@ampproject/remapping": { "version": "2.1.2", @@ -22369,8 +22443,7 @@ } }, "@bugsnag/plugin-react": { - "version": "7.19.0", - "requires": {} + "version": "7.19.0" }, "@bugsnag/safe-json-stringify": { "version": "6.0.0" @@ -22593,34 +22666,36 @@ }, "@csstools/postcss-unset-value": { "version": "1.0.2", - "dev": true, - "requires": {} + "dev": true }, "@csstools/selector-specificity": { "version": "2.0.2", - "dev": true, - "requires": {} + "dev": true }, "@eslint-community/eslint-utils": { "version": "4.4.0", + "dev": true, "requires": { "eslint-visitor-keys": "^3.3.0" }, "dependencies": { "eslint-visitor-keys": { - "version": "3.4.0" + "version": "3.4.0", + "dev": true } } }, "@eslint-community/regexpp": { "version": "4.8.0", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.0.tgz", - "integrity": "sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==" + "integrity": "sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==", + "dev": true }, "@eslint/eslintrc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -22636,12 +22711,14 @@ "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "globals": { "version": "13.21.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", + "dev": true, "requires": { "type-fest": "^0.20.2" } @@ -22650,6 +22727,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, "requires": { "argparse": "^2.0.1" } @@ -22657,14 +22735,16 @@ "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==" + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true } } }, "@eslint/js": { "version": "8.48.0", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.48.0.tgz", - "integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==" + "integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==", + "dev": true }, "@floating-ui/core": { "version": "1.7.3", @@ -22713,6 +22793,7 @@ "version": "0.11.11", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", + "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", @@ -22720,12 +22801,14 @@ } }, "@humanwhocodes/module-importer": { - "version": "1.0.1" + "version": "1.0.1", + "dev": true }, "@humanwhocodes/object-schema": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", @@ -23383,16 +23466,19 @@ }, "@nodelib/fs.scandir": { "version": "2.1.5", + "dev": true, "requires": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "@nodelib/fs.stat": { - "version": "2.0.5" + "version": "2.0.5", + "dev": true }, "@nodelib/fs.walk": { "version": "1.2.8", + "dev": true, "requires": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -24526,8 +24612,7 @@ "@vkontakte/vk-bridge-react": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@vkontakte/vk-bridge-react/-/vk-bridge-react-1.0.1.tgz", - "integrity": "sha512-+r0zxh1UUDcok2VtsPDc6jWHQezfsqHK3M9LAnTpKI9XyZlrgfEQA8cYsc0F8urOXUJ3FhEHXuJQjQGgK0Z5PA==", - "requires": {} + "integrity": "sha512-+r0zxh1UUDcok2VtsPDc6jWHQezfsqHK3M9LAnTpKI9XyZlrgfEQA8cYsc0F8urOXUJ3FhEHXuJQjQGgK0Z5PA==" }, "@vkontakte/vk-miniapps-deploy": { "version": "0.0.25", @@ -24741,7 +24826,8 @@ "acorn": { "version": "8.10.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==" + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dev": true }, "acorn-globals": { "version": "6.0.0", @@ -24759,14 +24845,13 @@ }, "acorn-import-assertions": { "version": "1.8.0", - "dev": true, - "requires": {} + "dev": true }, "acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "requires": {} + "dev": true }, "acorn-node": { "version": "1.8.2", @@ -24823,6 +24908,7 @@ }, "ajv": { "version": "6.12.6", + "dev": true, "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -24855,8 +24941,7 @@ }, "ajv-keywords": { "version": "3.5.2", - "dev": true, - "requires": {} + "dev": true }, "ansi-colors": { "version": "4.1.3", @@ -24875,7 +24960,8 @@ "dev": true }, "ansi-regex": { - "version": "5.0.1" + "version": "5.0.1", + "dev": true }, "ansi-styles": { "version": "4.3.0", @@ -25414,8 +25500,7 @@ }, "babel-plugin-named-asset-import": { "version": "0.3.8", - "dev": true, - "requires": {} + "dev": true }, "babel-plugin-polyfill-corejs2": { "version": "0.3.2", @@ -25658,7 +25743,8 @@ } }, "callsites": { - "version": "3.1.0" + "version": "3.1.0", + "dev": true }, "camel-case": { "version": "4.1.2", @@ -26166,6 +26252,7 @@ }, "cross-spawn": { "version": "7.0.3", + "dev": true, "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -26184,8 +26271,7 @@ }, "css-declaration-sorter": { "version": "6.3.1", - "dev": true, - "requires": {} + "dev": true }, "css-has-pseudo": { "version": "3.0.4", @@ -26268,8 +26354,7 @@ }, "css-prefers-color-scheme": { "version": "6.0.3", - "dev": true, - "requires": {} + "dev": true }, "css-select": { "version": "4.3.0", @@ -26356,8 +26441,7 @@ }, "cssnano-utils": { "version": "3.1.0", - "dev": true, - "requires": {} + "dev": true }, "csso": { "version": "4.2.0", @@ -27024,7 +27108,8 @@ "dev": true }, "deep-is": { - "version": "0.1.4" + "version": "0.1.4", + "dev": true }, "default-gateway": { "version": "6.0.3", @@ -27128,8 +27213,7 @@ "dignals-model": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/dignals-model/-/dignals-model-0.1.0.tgz", - "integrity": "sha512-+LmMZ4JUWL8/pniuF7avMfhzr4inJYm386JmAOiM7eBYLwN541kL9LnOQFcY65JRI+u6X0Gt+/JMK4tAZtctfQ==", - "requires": {} + "integrity": "sha512-+LmMZ4JUWL8/pniuF7avMfhzr4inJYm386JmAOiM7eBYLwN541kL9LnOQFcY65JRI+u6X0Gt+/JMK4tAZtctfQ==" }, "dignals-react": { "version": "0.1.27", @@ -27165,6 +27249,7 @@ }, "doctrine": { "version": "3.0.0", + "dev": true, "requires": { "esutils": "^2.0.2" } @@ -27465,6 +27550,7 @@ "version": "8.48.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz", "integrity": "sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==", + "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -27508,22 +27594,26 @@ "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "chalk": { "version": "4.1.2", + "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "escape-string-regexp": { - "version": "4.0.0" + "version": "4.0.0", + "dev": true }, "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, "requires": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -27532,10 +27622,12 @@ "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==" + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true }, "globals": { "version": "13.20.0", + "dev": true, "requires": { "type-fest": "^0.20.2" } @@ -27544,12 +27636,14 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, "requires": { "argparse": "^2.0.1" } }, "type-fest": { - "version": "0.20.2" + "version": "0.20.2", + "dev": true } } }, @@ -27867,8 +27961,7 @@ } }, "eslint-plugin-promise": { - "version": "6.1.1", - "requires": {} + "version": "6.1.1" }, "eslint-plugin-react": { "version": "7.32.2", @@ -28016,12 +28109,10 @@ }, "eslint-plugin-react-hooks": { "version": "4.6.0", - "dev": true, - "requires": {} + "dev": true }, "eslint-plugin-standard": { - "version": "5.0.0", - "requires": {} + "version": "5.0.0" }, "eslint-plugin-testing-library": { "version": "5.6.2", @@ -28116,6 +28207,7 @@ "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, "requires": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", @@ -28125,7 +28217,8 @@ "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==" + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true } } }, @@ -28135,12 +28228,14 @@ }, "esquery": { "version": "1.5.0", + "dev": true, "requires": { "estraverse": "^5.1.0" } }, "esrecurse": { "version": "4.3.0", + "dev": true, "requires": { "estraverse": "^5.2.0" } @@ -28283,7 +28378,8 @@ } }, "fast-deep-equal": { - "version": "3.1.3" + "version": "3.1.3", + "dev": true }, "fast-glob": { "version": "3.2.11", @@ -28306,13 +28402,16 @@ } }, "fast-json-stable-stringify": { - "version": "2.1.0" + "version": "2.1.0", + "dev": true }, "fast-levenshtein": { - "version": "2.0.6" + "version": "2.0.6", + "dev": true }, "fastq": { "version": "1.13.0", + "dev": true, "requires": { "reusify": "^1.0.4" } @@ -28338,6 +28437,7 @@ }, "file-entry-cache": { "version": "6.0.1", + "dev": true, "requires": { "flat-cache": "^3.0.4" } @@ -28434,6 +28534,7 @@ }, "find-up": { "version": "5.0.0", + "dev": true, "requires": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -28441,13 +28542,15 @@ }, "flat-cache": { "version": "3.0.4", + "dev": true, "requires": { "flatted": "^3.1.0", "rimraf": "^3.0.2" } }, "flatted": { - "version": "3.2.7" + "version": "3.2.7", + "dev": true }, "follow-redirects": { "version": "1.15.1", @@ -28661,6 +28764,7 @@ }, "glob-parent": { "version": "6.0.2", + "dev": true, "requires": { "is-glob": "^4.0.3" } @@ -28753,7 +28857,8 @@ "graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true }, "graphlib": { "version": "2.1.8", @@ -28955,8 +29060,7 @@ }, "icss-utils": { "version": "5.1.0", - "dev": true, - "requires": {} + "dev": true }, "idb": { "version": "7.0.2", @@ -28975,7 +29079,8 @@ "ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==" + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true }, "immer": { "version": "9.0.15", @@ -28983,13 +29088,15 @@ }, "import-fresh": { "version": "3.3.0", + "dev": true, "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" }, "dependencies": { "resolve-from": { - "version": "4.0.0" + "version": "4.0.0", + "dev": true } } }, @@ -29135,7 +29242,8 @@ "version": "2.0.0" }, "is-path-inside": { - "version": "3.0.3" + "version": "3.0.3", + "dev": true }, "is-plain-object": { "version": "2.0.4", @@ -29218,7 +29326,8 @@ "version": "0.0.2" }, "isexe": { - "version": "2.0.0" + "version": "2.0.0", + "dev": true }, "isobject": { "version": "3.0.1", @@ -29860,8 +29969,7 @@ }, "jest-pnp-resolver": { "version": "1.2.2", - "dev": true, - "requires": {} + "dev": true }, "jest-regex-util": { "version": "27.5.1", @@ -30529,10 +30637,12 @@ "dev": true }, "json-schema-traverse": { - "version": "0.4.1" + "version": "0.4.1", + "dev": true }, "json-stable-stringify-without-jsonify": { - "version": "1.0.1" + "version": "1.0.1", + "dev": true }, "json5": { "version": "1.0.2", @@ -30619,6 +30729,7 @@ }, "levn": { "version": "0.4.1", + "dev": true, "requires": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -30655,6 +30766,7 @@ }, "locate-path": { "version": "6.0.0", + "dev": true, "requires": { "p-locate": "^5.0.0" } @@ -30688,7 +30800,8 @@ "dev": true }, "lodash.merge": { - "version": "4.6.2" + "version": "4.6.2", + "dev": true }, "lodash.sortby": { "version": "4.7.0", @@ -31015,12 +31128,6 @@ "resolved": "https://registry.npmjs.org/moment-mini/-/moment-mini-2.29.4.tgz", "integrity": "sha512-uhXpYwHFeiTbY9KSgPPRoo1nt8OxNVdMVoTBYHfSEKeRkIkwGpO+gERmhuhBtzfaeOyTkykSrm2+noJBgqt3Hg==" }, - "monaco-editor": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.46.0.tgz", - "integrity": "sha512-ADwtLIIww+9FKybWscd7OCfm9odsFYHImBRI1v9AviGce55QY8raT+9ihH8jX/E/e6QVSGM+pKj4jSUSRmALNQ==", - "peer": true - }, "ms": { "version": "2.1.2" }, @@ -31037,7 +31144,8 @@ "dev": true }, "natural-compare": { - "version": "1.4.0" + "version": "1.4.0", + "dev": true }, "natural-compare-lite": { "version": "1.4.0", @@ -31447,6 +31555,7 @@ "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, "requires": { "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", @@ -31458,12 +31567,14 @@ }, "p-limit": { "version": "3.1.0", + "dev": true, "requires": { "yocto-queue": "^0.1.0" } }, "p-locate": { "version": "5.0.0", + "dev": true, "requires": { "p-limit": "^3.0.2" } @@ -31490,6 +31601,7 @@ }, "parent-module": { "version": "1.0.1", + "dev": true, "requires": { "callsites": "^3.0.0" } @@ -31528,13 +31640,15 @@ } }, "path-exists": { - "version": "4.0.0" + "version": "4.0.0", + "dev": true }, "path-is-absolute": { "version": "1.0.1" }, "path-key": { - "version": "3.1.1" + "version": "3.1.1", + "dev": true }, "path-parse": { "version": "1.0.7" @@ -31665,8 +31779,7 @@ }, "postcss-browser-comments": { "version": "4.0.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-calc": { "version": "8.2.4", @@ -31752,23 +31865,19 @@ }, "postcss-discard-comments": { "version": "5.1.2", - "dev": true, - "requires": {} + "dev": true }, "postcss-discard-duplicates": { "version": "5.1.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-discard-empty": { "version": "5.1.1", - "dev": true, - "requires": {} + "dev": true }, "postcss-discard-overridden": { "version": "5.1.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-double-position-gradients": { "version": "3.1.2", @@ -31787,8 +31896,7 @@ }, "postcss-flexbugs-fixes": { "version": "5.0.2", - "dev": true, - "requires": {} + "dev": true }, "postcss-focus-visible": { "version": "6.0.4", @@ -31806,13 +31914,11 @@ }, "postcss-font-variant": { "version": "5.0.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-gap-properties": { "version": "3.0.5", - "dev": true, - "requires": {} + "dev": true }, "postcss-image-set-function": { "version": "4.0.7", @@ -31832,8 +31938,7 @@ }, "postcss-initial": { "version": "4.0.1", - "dev": true, - "requires": {} + "dev": true }, "postcss-js": { "version": "4.0.0", @@ -31878,13 +31983,11 @@ }, "postcss-logical": { "version": "5.0.4", - "dev": true, - "requires": {} + "dev": true }, "postcss-media-minmax": { "version": "5.0.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-merge-longhand": { "version": "5.1.6", @@ -31938,8 +32041,7 @@ }, "postcss-modules-extract-imports": { "version": "3.0.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-modules-local-by-default": { "version": "4.0.0", @@ -31990,8 +32092,7 @@ }, "postcss-normalize-charset": { "version": "5.1.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-normalize-display-values": { "version": "5.1.0", @@ -32072,8 +32173,7 @@ }, "postcss-page-break": { "version": "3.0.4", - "dev": true, - "requires": {} + "dev": true }, "postcss-place": { "version": "7.0.5", @@ -32161,8 +32261,7 @@ }, "postcss-replace-overflow-wrap": { "version": "4.0.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-selector-not": { "version": "6.0.1", @@ -32234,7 +32333,8 @@ "dev": true }, "prelude-ls": { - "version": "1.2.1" + "version": "1.2.1", + "dev": true }, "prettier": { "version": "2.8.7", @@ -32329,7 +32429,8 @@ } }, "punycode": { - "version": "2.1.1" + "version": "2.1.1", + "dev": true }, "punycode.js": { "version": "2.3.1", @@ -32361,7 +32462,8 @@ "dev": true }, "queue-microtask": { - "version": "1.2.3" + "version": "1.2.3", + "dev": true }, "quick-lru": { "version": "5.1.1", @@ -32912,10 +33014,12 @@ "dev": true }, "reusify": { - "version": "1.0.4" + "version": "1.0.4", + "dev": true }, "rimraf": { "version": "3.0.2", + "dev": true, "requires": { "glob": "^7.1.3" } @@ -32962,6 +33066,7 @@ }, "run-parallel": { "version": "1.2.0", + "dev": true, "requires": { "queue-microtask": "^1.2.2" } @@ -33179,12 +33284,14 @@ }, "shebang-command": { "version": "2.0.0", + "dev": true, "requires": { "shebang-regex": "^3.0.0" } }, "shebang-regex": { - "version": "3.0.0" + "version": "3.0.0", + "dev": true }, "shell-quote": { "version": "1.7.3", @@ -33523,6 +33630,7 @@ }, "strip-ansi": { "version": "6.0.1", + "dev": true, "requires": { "ansi-regex": "^5.0.1" } @@ -33540,12 +33648,12 @@ "dev": true }, "strip-json-comments": { - "version": "3.1.1" + "version": "3.1.1", + "dev": true }, "style-loader": { "version": "3.3.1", - "dev": true, - "requires": {} + "dev": true }, "style-mod": { "version": "4.0.3" @@ -33807,7 +33915,8 @@ } }, "text-table": { - "version": "0.2.0" + "version": "0.2.0", + "dev": true }, "throat": { "version": "6.0.2", @@ -33855,8 +33964,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.2.tgz", "integrity": "sha512-Cbu4nIqnEdd+THNEsBdkolnOXhg0I8XteoHaEKgvsxpsbWda4IsUut2c187HxywQCvveojow0Dgw/amxtSKVkQ==", - "dev": true, - "requires": {} + "dev": true }, "ts-jest": { "version": "29.1.0", @@ -33949,6 +34057,7 @@ }, "type-check": { "version": "0.4.0", + "dev": true, "requires": { "prelude-ls": "^1.2.1" } @@ -34052,6 +34161,7 @@ }, "uri-js": { "version": "4.4.1", + "dev": true, "requires": { "punycode": "^2.1.0" } @@ -34065,8 +34175,7 @@ } }, "use-sync-external-store": { - "version": "1.2.0", - "requires": {} + "version": "1.2.0" }, "util-deprecate": { "version": "1.0.2" @@ -34360,8 +34469,7 @@ }, "ws": { "version": "8.8.1", - "dev": true, - "requires": {} + "dev": true } } }, @@ -34450,6 +34558,7 @@ }, "which": { "version": "2.0.2", + "dev": true, "requires": { "isexe": "^2.0.0" } @@ -34766,8 +34875,7 @@ }, "ws": { "version": "7.5.9", - "dev": true, - "requires": {} + "dev": true }, "xdg-basedir": { "version": "4.0.0" @@ -34823,7 +34931,8 @@ "dev": true }, "yocto-queue": { - "version": "0.1.0" + "version": "0.1.0", + "dev": true }, "zip-a-folder": { "version": "0.0.12", diff --git a/GPTutor-Frontend/package.json b/GPTutor-Frontend/package.json index 095e3477..e7013e40 100644 --- a/GPTutor-Frontend/package.json +++ b/GPTutor-Frontend/package.json @@ -22,8 +22,8 @@ "@monaco-editor/react": "^4.5.1", "@telegram-apps/sdk": "^1.1.3", "@types/node": "^12.0.0", - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", + "@types/react": "^18.0.28", + "@types/react-dom": "^18.0.28", "@uiw/react-codemirror": "^4.21.7", "@vkontakte/icons": "2.98.0", "@vkontakte/vk-bridge": "^2.14.1", diff --git a/GPTutor-Frontend/src/App.tsx b/GPTutor-Frontend/src/App.tsx index 9b5e254c..4b3bbb2c 100644 --- a/GPTutor-Frontend/src/App.tsx +++ b/GPTutor-Frontend/src/App.tsx @@ -68,14 +68,14 @@ import { transformVKBridgeAdaptivity } from "$/utility/strings"; import { MermaidPage } from "$/panels/MermaidPage"; import { AdditionalRequests } from "$/panels/AdditionalRequests"; import { AnecdoteMain } from "$/panels/AnecdoteMain"; -import AnecdoteGeneration from "./panels/AnecdoteGeneration/AnecdoteGeneration"; import { AnecdoteNews } from "$/panels/AnecdoteNews"; -import ApplicationInfoHumor from "./modals/ApplicationInfoHumor/ApplicationInfoHumor"; import { BingPanel } from "$/panels/BingPanel"; -import VKDocQuestionPanel from "./panels/VKDocQuestionPanel/VKDocQestionPanel"; import { VkDocQuestionRequest } from "$/panels/VkDocQuestionRequest"; +import AnecdoteGeneration from "./panels/AnecdoteGeneration/AnecdoteGeneration"; import { retrieveLaunchParams } from "@telegram-apps/sdk"; -import DocQuestionPanel from "$/panels/DocQuestionPanel"; +import ApplicationInfoHumor from "./modals/ApplicationInfoHumor/ApplicationInfoHumor"; +import VKDocQuestionPanel from "./panels/VKDocQuestionPanel/VKDocQestionPanel"; +import DocQuestionPanel from "./panels/ApiLLMPanel"; const App = () => { const location = useLocation(); @@ -103,8 +103,6 @@ const App = () => { window.location.search ); - console.log(vkBridgeAppearance); - function getPlatform() { if (appService.isTG()) { return "vkcom"; diff --git a/GPTutor-Frontend/src/components/AppContainer/AppContainer.tsx b/GPTutor-Frontend/src/components/AppContainer/AppContainer.tsx index 378c5662..118c7ce0 100644 --- a/GPTutor-Frontend/src/components/AppContainer/AppContainer.tsx +++ b/GPTutor-Frontend/src/components/AppContainer/AppContainer.tsx @@ -47,7 +47,6 @@ function AppContainer({ const offsetHeightTabbar = tabbarElem?.offsetHeight || 0; const offsetHeightFixedBottom = fixedBottom?.offsetHeight || 0; - console.log(offsetHeightTabbar); const offset = offsetHeightHeader + offsetHeightTabbar + offsetHeightFixedBottom; diff --git a/GPTutor-Frontend/src/index.tsx b/GPTutor-Frontend/src/index.tsx index 1eb35449..16eac8e7 100644 --- a/GPTutor-Frontend/src/index.tsx +++ b/GPTutor-Frontend/src/index.tsx @@ -12,12 +12,10 @@ import { OnboardingService } from "./services/OnboardingService"; import { NavigationContextProvider } from "$/NavigationContext"; import { adService } from "$/services/AdService"; import { appService } from "$/services/AppService"; -import { subscriptionsController } from "$/entity/subscriptions"; import { VkStorageService } from "$/services/VkStorageService"; import "react-lazy-load-image-component/src/effects/black-and-white.css"; import { userInfo } from "$/entity/user/UserInfo"; import { listenResize } from "./resizeWindow"; -import { additionalRequests } from "$/entity/additionalRequest/AdditionalRequests"; import { platformAdapter } from "$/services/PlatformAdapterService"; const isFirstVisitFlagName = "isFirstVisit"; @@ -39,20 +37,20 @@ async function VKInit() { storageService.set(isFirstVisitFlagName, String(true)); }); - if (appService.isStableArt()) { - await userInfo.getUserImageAgreement(); - } + // if (appService.isStableArt()) { + // await userInfo.getUserImageAgreement(); + // } await adService.showBannerAd(); - if (appService.isGPTutor()) { - await subscriptionsController.getSubscription("subscription_2"); - } - await additionalRequests.init(); + // if (appService.isGPTutor()) { + // await subscriptionsController.getSubscription("subscription_2"); + // } + // await additionalRequests.init(); } platformAdapter .webAppInit() .then(async () => { - await userInfo.getUserBalance(); + // await userInfo.getUserBalance(); if (appService.isVK()) { await VKInit(); diff --git a/GPTutor-Frontend/src/panels/ApiLLMPanel/ApiLLMPanel.module.css b/GPTutor-Frontend/src/panels/ApiLLMPanel/ApiLLMPanel.module.css new file mode 100644 index 00000000..4befc648 --- /dev/null +++ b/GPTutor-Frontend/src/panels/ApiLLMPanel/ApiLLMPanel.module.css @@ -0,0 +1,370 @@ +.container { + width: 100vw; +} + +.containerPlaceholder { + width: 100vw; + height: 100%; +} + +.apiCode { + display: flex; + align-items: center; + gap: 6px; +} + +.copyIcon { + background: var(--vkui--color_background_modal); + color: var(--vkui--color_text_accent_themed); + border-radius: 8px; + transition: all 0.2s ease; +} + +.copyIcon:hover { + background: var(--vkui--color_background_accent_themed); + color: var(--vkui--color_text_contrast_themed); +} + +.cardApi { + width: 100%; +} + +.actions { + display: flex; + gap: 8px; +} + +.cardProfile { + display: grid; +} + +.cardName { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; +} + +.subtitleText { + color: var(--vkui--color_text_secondary); +} + +/* Новые стили для API панели */ +.errorCard { + border-color: var(--vkui--color_stroke_negative); + background: var(--vkui--color_background_negative_tint); +} + +.errorHeader { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 8px; +} + +.responseHeader { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 12px; + justify-content: space-between; +} + +.responseText { + white-space: pre-wrap; + word-wrap: break-word; + line-height: 1.5; + padding: 12px; + background: var(--vkui--color_background_secondary); + border-radius: 8px; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; +} + +.codeHeader { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 12px; + padding-bottom: 8px; + border-bottom: 1px solid var(--vkui--color_separator_primary); +} + +.codeBlock { + background: var(--vkui--color_background_secondary); + border-radius: 8px; + padding: 16px; + overflow-x: auto; + font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace; + font-size: 13px; + line-height: 1.4; + margin: 0; + border: 1px solid var(--vkui--color_separator_primary); +} + +.codeBlock code { + color: var(--vkui--color_text_primary); + background: none; + padding: 0; + font-size: inherit; + font-family: inherit; +} + +/* Стили для табов */ +.tabContent { + padding-bottom: 80px; +} + +/* Улучшенные стили для слайдеров */ +.sliderContainer { + padding: 8px 0; +} + +.parameterDescription { + color: var(--vkui--color_text_secondary); + font-size: 14px; + margin-top: 4px; + line-height: 1.3; +} + +/* Стили для форм */ +.formGroup { + margin-bottom: 20px; +} + +.apiKeyInput { + font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace; +} + +/* Анимации */ +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.fadeIn { + animation: fadeIn 0.3s ease-out; +} + +/* Адаптивность */ +@media (max-width: 768px) { + .codeBlock { + font-size: 12px; + padding: 12px; + } + + .responseText { + font-size: 14px; + padding: 10px; + } +} + +/* Улучшенные стили для карточек */ +.apiCard { + transition: all 0.2s ease; + border-radius: 12px; +} + +.apiCard:hover { + transform: translateY(-2px); + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); +} + +/* Стили для статусных индикаторов */ +.statusSuccess { + color: var(--vkui--color_text_positive); +} + +.statusError { + color: var(--vkui--color_text_negative); +} + +.statusPending { + color: var(--vkui--color_text_secondary); +} + +/* Стили для баланса */ +.balanceCard { + background: linear-gradient(135deg, var(--vkui--color_background_accent_themed) 0%, var(--vkui--color_background_accent_tint_themed) 100%); + border: none; +} + +.balanceHeader { + display: flex; + align-items: center; + gap: 12px; +} + +.balanceSubtitle { + color: var(--vkui--color_text_secondary); + margin-top: 2px; +} + +.balanceActions { + display: flex; + flex-direction: column; + gap: 12px; +} + +.costEstimate { + display: flex; + align-items: center; + gap: 8px; + padding: 8px 12px; + background: var(--vkui--color_background_warning_tint); + border-radius: 8px; + font-size: 13px; +} + +/* Стили для примеров */ +.examplesGrid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 12px; + margin-bottom: 16px; +} + +.exampleCard { + transition: all 0.2s ease; + cursor: pointer; +} + +.exampleCard:hover { + transform: translateY(-2px); + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12); +} + +.exampleHeader { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 8px; +} + +.exampleDescription { + color: var(--vkui--color_text_secondary); + font-size: 14px; + line-height: 1.4; +} + +/* Улучшенные стили для кода */ +.codeActions { + display: flex; + align-items: center; + gap: 8px; +} + +.downloadIcon { + background: var(--vkui--color_background_positive_tint); + color: var(--vkui--color_text_positive); + border-radius: 8px; + transition: all 0.2s ease; +} + +.downloadIcon:hover { + background: var(--vkui--color_background_positive_themed); + color: var(--vkui--color_text_contrast_themed); +} + +/* Улучшенный код блок */ +.codeBlock { + background: var(--vkui--color_background_secondary); + border-radius: 12px; + padding: 20px; + overflow-x: auto; + font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace; + font-size: 13px; + line-height: 1.5; + margin: 0; + border: 1px solid var(--vkui--color_separator_primary); + position: relative; +} + +.codeBlock::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 3px; + background: linear-gradient(90deg, #ff6b6b, #4ecdc4, #45b7d1, #96ceb4); + border-radius: 12px 12px 0 0; +} + +/* Улучшенные стили для заголовков кода */ +.codeHeader { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 16px; + padding-bottom: 12px; + border-bottom: 2px solid var(--vkui--color_separator_primary); +} + +/* Стили для мобильных устройств */ +@media (max-width: 768px) { + .examplesGrid { + grid-template-columns: 1fr; + gap: 8px; + } + + .balanceHeader { + flex-direction: column; + align-items: flex-start; + gap: 8px; + } + + .codeActions { + flex-direction: column; + gap: 4px; + } +} + +/* Анимация для карточек */ +.fadeInUp { + animation: fadeInUp 0.4s ease-out; +} + +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* Стили для статистики использования */ +.usageStats { + display: flex; + justify-content: space-between; + align-items: center; + padding: 12px 16px; + background: var(--vkui--color_background_secondary); + border-radius: 8px; + margin-top: 12px; +} + +.statItem { + text-align: center; +} + +.statValue { + font-weight: 600; + font-size: 16px; + color: var(--vkui--color_text_primary); +} + +.statLabel { + font-size: 12px; + color: var(--vkui--color_text_secondary); + margin-top: 2px; +} diff --git a/GPTutor-Frontend/src/panels/ApiLLMPanel/index.tsx b/GPTutor-Frontend/src/panels/ApiLLMPanel/index.tsx new file mode 100644 index 00000000..3323f50c --- /dev/null +++ b/GPTutor-Frontend/src/panels/ApiLLMPanel/index.tsx @@ -0,0 +1,801 @@ +import * as React from "react"; +import { + Button, + Card, + CardGrid, + Div, + FormItem, + FormLayoutGroup, + Input, + Textarea, + Slider, + Select, + Checkbox, + IconButton, + Panel, + PanelHeader, + PanelHeaderBack, + Spacing, + Title, + Caption, + Headline, + Text, + Separator, + Group, + Header, + SimpleCell, + Switch, + FixedLayout, + Tabbar, + TabbarItem, +} from "@vkontakte/vkui"; +import { AppContainer } from "$/components/AppContainer"; +import { useNavigationContext } from "$/NavigationContext"; +import PanelTitle from "$/components/PanelTitle"; +import { CardBlock } from "$/components/CardBlock"; +import { + Icon20CopyOutline, + Icon28DocumentOutline, + Icon24ReplayOutline, + Icon28SettingsOutline, + Icon24QuestionOutline, + Icon24KeyOutline, + Icon24BrainOutline, + Icon20CheckCircleFillGreen, + Icon24ErrorCircleFillRed, + Icon24MoneyCircleOutline, + Icon24AddCircleOutline, + Icon24LightbulbOutline, + Icon24InfoCircleOutline, + Icon24DollarCircleOutline, + Icon24PlayCircle, +} from "@vkontakte/icons"; + +import classes from "./ApiLLMPanel.module.css"; +import TertiaryTitle from "$/components/TertiaryTitle"; +import { AppDiv } from "$/components/AppDiv"; + +interface IProps { + id: string; +} + +interface OpenAIParams { + apiKey: string; + model: string; + temperature: number; + maxTokens: number; + topP: number; + frequencyPenalty: number; + presencePenalty: number; + systemPrompt: string; + userMessage: string; + stream: boolean; +} + +interface UserBalance { + balance: number; + currency: string; +} + +interface PromptExample { + title: string; + systemPrompt: string; + userMessage: string; + description: string; +} + +function ApiLLMPanel({ id }: IProps) { + const { goBack } = useNavigationContext(); + const [activeTab, setActiveTab] = React.useState("settings"); + const [isLoading, setIsLoading] = React.useState(false); + const [response, setResponse] = React.useState(""); + const [error, setError] = React.useState(""); + const [userBalance, setUserBalance] = React.useState({ + balance: 15.5, + currency: "USD", + }); + const [estimatedCost, setEstimatedCost] = React.useState(0); + + const [params, setParams] = React.useState({ + apiKey: "", + model: "gpt-3.5-turbo", + temperature: 0.7, + maxTokens: 1000, + topP: 1, + frequencyPenalty: 0, + presencePenalty: 0, + systemPrompt: "You are a helpful assistant.", + userMessage: "", + stream: false, + }); + + const models = [ + { label: "GPT-3.5 Turbo", value: "gpt-3.5-turbo" }, + { label: "GPT-4", value: "gpt-4" }, + { label: "GPT-4 Turbo", value: "gpt-4-turbo-preview" }, + { label: "GPT-4o", value: "gpt-4o" }, + { label: "GPT-4o Mini", value: "gpt-4o-mini" }, + ]; + + const promptExamples: PromptExample[] = [ + { + title: "Программист-помощник", + description: "Помощь с написанием и отладкой кода", + systemPrompt: + "Ты опытный программист. Помогай писать чистый, эффективный код и объясняй сложные концепции простым языком.", + userMessage: "Напиши функцию на Python для сортировки массива пузырьком", + }, + { + title: "Переводчик", + description: "Профессиональный перевод текстов", + systemPrompt: + "Ты профессиональный переводчик. Переводи тексты точно, сохраняя смысл и стиль оригинала.", + userMessage: + "Переведи на английский: 'Привет, как дела? Надеюсь, у тебя все хорошо.'", + }, + { + title: "Аналитик данных", + description: "Анализ и интерпретация данных", + systemPrompt: + "Ты эксперт по анализу данных. Помогай интерпретировать данные, находить закономерности и делать выводы.", + userMessage: "Объясни, что такое корреляция и как её интерпретировать", + }, + { + title: "Творческий писатель", + description: "Создание креативного контента", + systemPrompt: + "Ты творческий писатель с богатым воображением. Создавай интересные истории, стихи и креативный контент.", + userMessage: + "Напиши короткий рассказ о роботе, который учится быть человеком", + }, + ]; + + const modelPricing = { + "gpt-3.5-turbo": { input: 0.0015, output: 0.002 }, + "gpt-4": { input: 0.03, output: 0.06 }, + "gpt-4-turbo-preview": { input: 0.01, output: 0.03 }, + "gpt-4o": { input: 0.005, output: 0.015 }, + "gpt-4o-mini": { input: 0.00015, output: 0.0006 }, + }; + + const handleParamChange = (key: keyof OpenAIParams, value: any) => { + setParams((prev) => ({ ...prev, [key]: value })); + if ( + key === "model" || + key === "maxTokens" || + key === "userMessage" || + key === "systemPrompt" + ) { + calculateEstimatedCost({ ...params, [key]: value }); + } + }; + + const calculateEstimatedCost = (currentParams: OpenAIParams) => { + const pricing = + modelPricing[currentParams.model as keyof typeof modelPricing]; + if (!pricing) return; + + // Примерная оценка токенов (1 токен ≈ 4 символа) + const inputTokens = Math.ceil( + (currentParams.systemPrompt.length + currentParams.userMessage.length) / 4 + ); + const outputTokens = currentParams.maxTokens; + + const inputCost = (inputTokens / 1000) * pricing.input; + const outputCost = (outputTokens / 1000) * pricing.output; + const totalCost = inputCost + outputCost; + + setEstimatedCost(totalCost); + }; + + const applyPromptExample = (example: PromptExample) => { + setParams((prev) => ({ + ...prev, + systemPrompt: example.systemPrompt, + userMessage: example.userMessage, + })); + calculateEstimatedCost({ + ...params, + systemPrompt: example.systemPrompt, + userMessage: example.userMessage, + }); + }; + + const handleTopUpBalance = () => { + // Здесь будет логика пополнения баланса + alert("Функция пополнения баланса будет реализована позже"); + }; + + React.useEffect(() => { + calculateEstimatedCost(params); + }, [params.model, params.maxTokens, params.userMessage, params.systemPrompt]); + + const handleTestAPI = async () => { + if (!params.apiKey.trim()) { + setError("API ключ обязателен"); + return; + } + if (!params.userMessage.trim()) { + setError("Сообщение пользователя обязательно"); + return; + } + + setIsLoading(true); + setError(""); + setResponse(""); + + try { + const requestBody = { + model: params.model, + messages: [ + { role: "system", content: params.systemPrompt }, + { role: "user", content: params.userMessage }, + ], + temperature: params.temperature, + max_tokens: params.maxTokens, + top_p: params.topP, + frequency_penalty: params.frequencyPenalty, + presence_penalty: params.presencePenalty, + stream: params.stream, + }; + + const response = await fetch( + "https://api.openai.com/v1/chat/completions", + { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${params.apiKey}`, + }, + body: JSON.stringify(requestBody), + } + ); + + const data = await response.json(); + + if (!response.ok) { + throw new Error(data.error?.message || "Ошибка API"); + } + + setResponse(data.choices[0].message.content); + } catch (err: any) { + setError(err.message || "Произошла ошибка"); + } finally { + setIsLoading(false); + } + }; + + const copyToClipboard = (text: string) => { + navigator.clipboard.writeText(text); + }; + + const executeCode = (codeType: "python" | "javascript" | "curl") => { + let code = ""; + switch (codeType) { + case "python": + code = generatePythonCode(); + break; + case "javascript": + code = generateJavaScriptCode(); + break; + case "curl": + code = generateCurlCode(); + break; + } + + const blob = new Blob([code], { type: "text/plain" }); + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = `openai_example.${ + codeType === "curl" ? "sh" : codeType === "python" ? "py" : "js" + }`; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + }; + + const generatePythonCode = () => { + return `import openai +import json + +# Настройка API ключа +openai.api_key = "${params.apiKey || "YOUR_API_KEY"}" + +# Параметры запроса +response = openai.ChatCompletion.create( + model="${params.model}", + messages=[ + {"role": "system", "content": "${params.systemPrompt}"}, + {"role": "user", "content": "${params.userMessage || "Ваше сообщение"}"} + ], + temperature=${params.temperature}, + max_tokens=${params.maxTokens}, + top_p=${params.topP}, + frequency_penalty=${params.frequencyPenalty}, + presence_penalty=${params.presencePenalty}, + stream=${params.stream ? "True" : "False"} +) + +print(json.dumps(response, indent=2, ensure_ascii=False))`; + }; + + const generateJavaScriptCode = () => { + return `const OpenAI = require('openai'); + +const openai = new OpenAI({ + apiKey: '${params.apiKey || "YOUR_API_KEY"}', +}); + +async function main() { + const completion = await openai.chat.completions.create({ + messages: [ + { role: 'system', content: '${params.systemPrompt}' }, + { role: 'user', content: '${params.userMessage || "Ваше сообщение"}' } + ], + model: '${params.model}', + temperature: ${params.temperature}, + max_tokens: ${params.maxTokens}, + top_p: ${params.topP}, + frequency_penalty: ${params.frequencyPenalty}, + presence_penalty: ${params.presencePenalty}, + stream: ${params.stream} + }); + + console.log(completion.choices[0].message.content); +} + +main();`; + }; + + const generateCurlCode = () => { + const requestBody = { + model: params.model, + messages: [ + { role: "system", content: params.systemPrompt }, + { role: "user", content: params.userMessage || "Ваше сообщение" }, + ], + temperature: params.temperature, + max_tokens: params.maxTokens, + top_p: params.topP, + frequency_penalty: params.frequencyPenalty, + presence_penalty: params.presencePenalty, + stream: params.stream, + }; + + return `curl https://api.openai.com/v1/chat/completions \\ + -H "Content-Type: application/json" \\ + -H "Authorization: Bearer ${params.apiKey || "YOUR_API_KEY"}" \\ + -d '${JSON.stringify(requestBody, null, 2)}'`; + }; + + return ( + + }> + + + } + childrenWithHeight={(height) => ( +
+ + + setActiveTab("settings")} + selected={activeTab === "settings"} + text="Настройки" + > + + + setActiveTab("test")} + selected={activeTab === "test"} + text="Тест API" + > + + + setActiveTab("code")} + selected={activeTab === "code"} + text="Примеры кода" + > + + + + + +
+ {activeTab === "settings" && ( + +
Баланс пользователя
+ +
+
+ +
+ + ${userBalance.balance.toFixed(2)}{" "} + {userBalance.currency} + + + Доступный баланс + +
+
+ +
+ + {estimatedCost > 0 && ( +
+ + + Примерная стоимость запроса: $ + {estimatedCost.toFixed(6)} + +
+ )} +
+
+
+ + + +
API Конфигурация
+ + + + handleParamChange("apiKey", e.target.value) + } + before={} + /> + + + +