diff --git a/bun.lock b/bun.lock index b3ae8a6..b2dd02a 100644 --- a/bun.lock +++ b/bun.lock @@ -6,37 +6,37 @@ "name": "firefly-tools", "dependencies": { "@next/bundle-analyzer": "16.1.6", - "@tanstack/react-query": "^5.90.20", - "axios": "^1.13.4", - "fast-average-color": "^9.5.0", - "framer-motion": "^12.29.2", - "html2canvas-pro": "^1.6.6", - "lru-cache": "^11.2.5", + "@tanstack/react-query": "^5.100.10", + "axios": "^1.16.1", + "fast-average-color": "^9.5.2", + "framer-motion": "^12.38.0", + "html2canvas-pro": "^1.6.7", + "lru-cache": "^11.3.6", "lucide-react": "^0.563.0", "next": "16.1.6", - "next-intl": "^4.8.2", + "next-intl": "^4.12.0", "prismjs": "^1.30.0", "react": "19.2.4", "react-dom": "19.2.4", "react-select": "^5.10.2", "react-simple-code-editor": "^0.14.1", - "react-toastify": "^11.0.5", + "react-toastify": "^11.1.0", "sharp": "^0.34.5", - "zod": "^4.3.6", - "zustand": "^5.0.11", + "zod": "^4.4.3", + "zustand": "^5.0.13", }, "devDependencies": { - "@tailwindcss/postcss": "^4.1.18", + "@tailwindcss/postcss": "^4.3.0", "@types/jest": "^30.0.0", - "@types/node": "^25.1.0", + "@types/node": "^25.8.0", "@types/react": "19.2.6", "@types/react-dom": "19.2.3", - "baseline-browser-mapping": "^2.9.19", - "daisyui": "^5.5.14", - "eslint": "^9.39.2", + "baseline-browser-mapping": "^2.10.29", + "daisyui": "^5.5.19", + "eslint": "^9.39.4", "eslint-config-next": "16.1.6", "tailwind-scrollbar": "^4.0.2", - "tailwindcss": "^4.1.18", + "tailwindcss": "^4.3.0", "ts-to-zod": "^5.1.0", "typescript": "^5.9.3", }, @@ -121,15 +121,15 @@ "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="], - "@eslint/config-array": ["@eslint/config-array@0.21.1", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA=="], + "@eslint/config-array": ["@eslint/config-array@0.21.2", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.5" } }, "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw=="], "@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "^0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="], "@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="], - "@eslint/eslintrc": ["@eslint/eslintrc@3.3.3", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ=="], + "@eslint/eslintrc": ["@eslint/eslintrc@3.3.5", "", { "dependencies": { "ajv": "^6.14.0", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" } }, "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg=="], - "@eslint/js": ["@eslint/js@9.39.2", "", {}, "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA=="], + "@eslint/js": ["@eslint/js@9.39.4", "", {}, "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw=="], "@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="], @@ -143,13 +143,13 @@ "@formatjs/ecma402-abstract": ["@formatjs/ecma402-abstract@3.1.0", "", { "dependencies": { "@formatjs/fast-memoize": "3.1.0", "@formatjs/intl-localematcher": "0.8.0", "decimal.js": "^10.6.0", "tslib": "^2.8.1" } }, "sha512-CjP1sUzM7XiQW6YluDreN+dMvcKZysO/J4ikvuDjDyd6nSOoSqAK9gvD1s75ZFaJVXtYOsz+y3CUXPZ1sKxcxw=="], - "@formatjs/fast-memoize": ["@formatjs/fast-memoize@3.1.0", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-b5mvSWCI+XVKiz5WhnBCY3RJ4ZwfjAidU0yVlKa3d3MSgKmH1hC3tBGEAtYyN5mqL7N0G5x0BOUYyO8CEupWgg=="], + "@formatjs/fast-memoize": ["@formatjs/fast-memoize@3.1.5", "", {}, "sha512-KLi3fan6WnCHmigd9pmEEN8Hid0v4wiFBW576M/d07KMWYecf1CvyMI3n34vCmHT4AoVqG2n702kiHbXjzZX2A=="], "@formatjs/icu-messageformat-parser": ["@formatjs/icu-messageformat-parser@3.5.0", "", { "dependencies": { "@formatjs/ecma402-abstract": "3.1.0", "@formatjs/icu-skeleton-parser": "2.1.0", "tslib": "^2.8.1" } }, "sha512-Q01XuvtbDVCJQsG/E2MSfMZ+UdUoZV8v4Aex8tTH44SqKJZCeu5LjuclaKFUS0o1YoXndfEinJen5k1T1GR1vg=="], "@formatjs/icu-skeleton-parser": ["@formatjs/icu-skeleton-parser@2.1.0", "", { "dependencies": { "@formatjs/ecma402-abstract": "3.1.0", "tslib": "^2.8.1" } }, "sha512-wNer4imHDFBVAJnMb2OGoSyM4wL/uuLnuo5mrenliqkDaNjRbG4jzlJcwTTDEBhai8iCjnzUsE7xwNJC29SfWw=="], - "@formatjs/intl-localematcher": ["@formatjs/intl-localematcher@0.5.10", "", { "dependencies": { "tslib": "2" } }, "sha512-af3qATX+m4Rnd9+wHcjJ4w2ijq+rAVP3CCinJQvFv1kgSu1W6jypUmvleJxcewdxmutM8dmIRZFxO/IQBZmP2Q=="], + "@formatjs/intl-localematcher": ["@formatjs/intl-localematcher@0.8.8", "", { "dependencies": { "@formatjs/fast-memoize": "3.1.5" } }, "sha512-pBr2hVKWvkHVnfXegW+53NT9U2uaVQCc+EgzLPCCwXqBA3nvM5fPbK9IcJlNjV+NMKGyZ2F3ZSG78iGdxAAqbA=="], "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], @@ -329,39 +329,39 @@ "@swc/types": ["@swc/types@0.1.25", "", { "dependencies": { "@swc/counter": "^0.1.3" } }, "sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g=="], - "@tailwindcss/node": ["@tailwindcss/node@4.1.18", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.1", "lightningcss": "1.30.2", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.1.18" } }, "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ=="], + "@tailwindcss/node": ["@tailwindcss/node@4.3.0", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.21.0", "jiti": "^2.6.1", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.3.0" } }, "sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g=="], - "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.18", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.18", "@tailwindcss/oxide-darwin-arm64": "4.1.18", "@tailwindcss/oxide-darwin-x64": "4.1.18", "@tailwindcss/oxide-freebsd-x64": "4.1.18", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18", "@tailwindcss/oxide-linux-arm64-musl": "4.1.18", "@tailwindcss/oxide-linux-x64-gnu": "4.1.18", "@tailwindcss/oxide-linux-x64-musl": "4.1.18", "@tailwindcss/oxide-wasm32-wasi": "4.1.18", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18", "@tailwindcss/oxide-win32-x64-msvc": "4.1.18" } }, "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A=="], + "@tailwindcss/oxide": ["@tailwindcss/oxide@4.3.0", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.3.0", "@tailwindcss/oxide-darwin-arm64": "4.3.0", "@tailwindcss/oxide-darwin-x64": "4.3.0", "@tailwindcss/oxide-freebsd-x64": "4.3.0", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.0", "@tailwindcss/oxide-linux-arm64-gnu": "4.3.0", "@tailwindcss/oxide-linux-arm64-musl": "4.3.0", "@tailwindcss/oxide-linux-x64-gnu": "4.3.0", "@tailwindcss/oxide-linux-x64-musl": "4.3.0", "@tailwindcss/oxide-wasm32-wasi": "4.3.0", "@tailwindcss/oxide-win32-arm64-msvc": "4.3.0", "@tailwindcss/oxide-win32-x64-msvc": "4.3.0" } }, "sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg=="], - "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.18", "", { "os": "android", "cpu": "arm64" }, "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q=="], + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.3.0", "", { "os": "android", "cpu": "arm64" }, "sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng=="], - "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.18", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A=="], + "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.3.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ=="], - "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.18", "", { "os": "darwin", "cpu": "x64" }, "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw=="], + "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.3.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA=="], - "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.18", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA=="], + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.3.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ=="], - "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18", "", { "os": "linux", "cpu": "arm" }, "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA=="], + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0", "", { "os": "linux", "cpu": "arm" }, "sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA=="], - "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.18", "", { "os": "linux", "cpu": "arm64" }, "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw=="], + "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.3.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg=="], - "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.18", "", { "os": "linux", "cpu": "arm64" }, "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg=="], + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.3.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ=="], - "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.18", "", { "os": "linux", "cpu": "x64" }, "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g=="], + "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.3.0", "", { "os": "linux", "cpu": "x64" }, "sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ=="], - "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.18", "", { "os": "linux", "cpu": "x64" }, "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ=="], + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.3.0", "", { "os": "linux", "cpu": "x64" }, "sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg=="], - "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.18", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.1.0", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.4.0" }, "cpu": "none" }, "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA=="], + "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.3.0", "", { "dependencies": { "@emnapi/core": "^1.10.0", "@emnapi/runtime": "^1.10.0", "@emnapi/wasi-threads": "^1.2.1", "@napi-rs/wasm-runtime": "^1.1.4", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA=="], - "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.18", "", { "os": "win32", "cpu": "arm64" }, "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA=="], + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.3.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ=="], - "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.18", "", { "os": "win32", "cpu": "x64" }, "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q=="], + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.3.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA=="], - "@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.18", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.18", "@tailwindcss/oxide": "4.1.18", "postcss": "^8.4.41", "tailwindcss": "4.1.18" } }, "sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g=="], + "@tailwindcss/postcss": ["@tailwindcss/postcss@4.3.0", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.3.0", "@tailwindcss/oxide": "4.3.0", "postcss": "^8.5.10", "tailwindcss": "4.3.0" } }, "sha512-Jm05Tjx+9yCLGv5qw1c+84Psds8MnyrEQYCB+FFk2lgGiUjlRqdxke4mVTuYrj2xnVZqKim2Apr5ySuQRYAw/w=="], - "@tanstack/query-core": ["@tanstack/query-core@5.90.20", "", {}, "sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg=="], + "@tanstack/query-core": ["@tanstack/query-core@5.100.10", "", {}, "sha512-8UR0yJR+GiQ40m3lPhUr0xbfAupe6GSQiksSBSa9SM2NjezFyxXCIA69/lz8cSoNKZLrw1/PktIyQBJcVeMi3w=="], - "@tanstack/react-query": ["@tanstack/react-query@5.90.20", "", { "dependencies": { "@tanstack/query-core": "5.90.20" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-vXBxa+qeyveVO7OA0jX1z+DeyCA4JKnThKv411jd5SORpBKgkcVnYKCiBgECvADvniBX7tobwBmg01qq9JmMJw=="], + "@tanstack/react-query": ["@tanstack/react-query@5.100.10", "", { "dependencies": { "@tanstack/query-core": "5.100.10" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-FLaZf2RCrA/Zgp4aiu5tG3TyasTRO7aZ99skxQpr3Hg/zXOhu6yq5FZCYQ/tRaJtM9ylnoK8tFK7PolXQadv6Q=="], "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], @@ -379,7 +379,7 @@ "@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="], - "@types/node": ["@types/node@25.1.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA=="], + "@types/node": ["@types/node@25.8.0", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ=="], "@types/parse-json": ["@types/parse-json@4.0.2", "", {}, "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw=="], @@ -463,7 +463,9 @@ "acorn-walk": ["acorn-walk@8.3.4", "", { "dependencies": { "acorn": "^8.11.0" } }, "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g=="], - "ajv": ["ajv@6.12.6", "", { "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" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], + "agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="], + + "ajv": ["ajv@6.15.0", "", { "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" } }, "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw=="], "ansi-escapes": ["ansi-escapes@4.3.2", "", { "dependencies": { "type-fest": "^0.21.3" } }, "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ=="], @@ -505,7 +507,7 @@ "axe-core": ["axe-core@4.11.1", "", {}, "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A=="], - "axios": ["axios@1.13.4", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg=="], + "axios": ["axios@1.16.1", "", { "dependencies": { "follow-redirects": "^1.16.0", "form-data": "^4.0.5", "https-proxy-agent": "^5.0.1", "proxy-from-env": "^2.1.0" } }, "sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A=="], "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], @@ -515,7 +517,7 @@ "base64-arraybuffer": ["base64-arraybuffer@1.0.2", "", {}, "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ=="], - "baseline-browser-mapping": ["baseline-browser-mapping@2.9.19", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg=="], + "baseline-browser-mapping": ["baseline-browser-mapping@2.10.29", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-Asa2krT+XTPZINCS+2QcyS8WTkObE77RwkydwF7h6DmnKqbvlalz93m/dnphUyCa6SWSP51VgtEUf2FN+gelFQ=="], "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], @@ -573,7 +575,7 @@ "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], - "daisyui": ["daisyui@5.5.14", "", {}, "sha512-L47rvw7I7hK68TA97VB8Ee0woHew+/ohR6Lx6Ah/krfISOqcG4My7poNpX5Mo5/ytMxiR40fEaz6njzDi7cuSg=="], + "daisyui": ["daisyui@5.5.19", "", {}, "sha512-pbFAkl1VCEh/MPCeclKL61I/MqRIFFhNU7yiXoDDRapXN4/qNCoMxeCCswyxEEhqL5eiTTfwHvucFtOE71C9sA=="], "damerau-levenshtein": ["damerau-levenshtein@1.0.8", "", {}, "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA=="], @@ -613,7 +615,7 @@ "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], - "enhanced-resolve": ["enhanced-resolve@5.18.4", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q=="], + "enhanced-resolve": ["enhanced-resolve@5.21.3", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-QyL119InA+XXEkNLNTPCXPugSvOfhwv0JOlGNzvxs0hZaiHLNvXSpudUWsOlsXGWJh8G6ckCScEkVHfX3kw/2Q=="], "environment": ["environment@1.1.0", "", {}, "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q=="], @@ -639,7 +641,7 @@ "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], - "eslint": ["eslint@9.39.2", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.39.2", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw=="], + "eslint": ["eslint@9.39.4", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.2", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.5", "@eslint/js": "9.39.4", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ=="], "eslint-config-next": ["eslint-config-next@16.1.6", "", { "dependencies": { "@next/eslint-plugin-next": "16.1.6", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-import": "^2.32.0", "eslint-plugin-jsx-a11y": "^6.10.0", "eslint-plugin-react": "^7.37.0", "eslint-plugin-react-hooks": "^7.0.0", "globals": "16.4.0", "typescript-eslint": "^8.46.0" }, "peerDependencies": { "eslint": ">=9.0.0", "typescript": ">=3.3.1" }, "optionalPeers": ["typescript"] }, "sha512-vKq40io2B0XtkkNDYyleATwblNt8xuh3FWp8SpSz3pt7P01OkBFlKsJZ2mWt5WsCySlDQLckb1zMY9yE9Qy0LA=="], @@ -675,7 +677,7 @@ "expect": ["expect@30.2.0", "", { "dependencies": { "@jest/expect-utils": "30.2.0", "@jest/get-type": "30.1.0", "jest-matcher-utils": "30.2.0", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw=="], - "fast-average-color": ["fast-average-color@9.5.0", "", {}, "sha512-nC6x2YIlJ9xxgkMFMd1BNoM1ctMjNoRKfRliPmiEWW3S6rLTHiQcy9g3pt/xiKv/D0NAAkhb9VyV+WJFvTqMGg=="], + "fast-average-color": ["fast-average-color@9.5.2", "", {}, "sha512-FbaU8iPTPljP7tmnVhXbCyASNw/zxnmaNDf88gn5pTXlNvejl9w4FapeWMh6UNDwIjhJJU28EPfQWwW032YgPA=="], "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], @@ -703,13 +705,13 @@ "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], - "follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="], + "follow-redirects": ["follow-redirects@1.16.0", "", { "peerDependencies": { "debug": "*" }, "optionalPeers": ["debug"] }, "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw=="], "for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="], "form-data": ["form-data@4.0.5", "", { "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" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="], - "framer-motion": ["framer-motion@12.29.2", "", { "dependencies": { "motion-dom": "^12.29.2", "motion-utils": "^12.29.2", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-lSNRzBJk4wuIy0emYQ/nfZ7eWhqud2umPKw2QAQki6uKhZPKm2hRQHeQoHTG9MIvfobb+A/LbEWPJU794ZUKrg=="], + "framer-motion": ["framer-motion@12.38.0", "", { "dependencies": { "motion-dom": "^12.38.0", "motion-utils": "^12.36.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g=="], "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], @@ -767,9 +769,11 @@ "html-escaper": ["html-escaper@2.0.2", "", {}, "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="], - "html2canvas-pro": ["html2canvas-pro@1.6.6", "", { "dependencies": { "css-line-break": "^2.1.0", "text-segmentation": "^1.0.3" } }, "sha512-5mRhTXZhv4B0kIcsn3bFBjol2o8vzP35mhtxdXBGPA3V3gZd6Sa2PIIFbT//DiqAX8UuywlcJit5jRKej4nV4Q=="], + "html2canvas-pro": ["html2canvas-pro@1.6.7", "", { "dependencies": { "css-line-break": "^2.1.0", "text-segmentation": "^1.0.3" } }, "sha512-BzuCTXx0jf2TfnrJrtjMCY1FR9rxlPdy7yLWt9ZMhZm7Ylaw9MLb7agSheqv2mT/ARduBHDAqvJIFlbxrZfyOA=="], - "icu-minify": ["icu-minify@4.8.2", "", { "dependencies": { "@formatjs/icu-messageformat-parser": "^3.4.0" } }, "sha512-LHBQV+skKkjZSPd590pZ7ZAHftUgda3eFjeuNwA8/15L8T8loCNBktKQyTlkodAU86KovFXeg/9WntlAo5wA5A=="], + "https-proxy-agent": ["https-proxy-agent@5.0.1", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="], + + "icu-minify": ["icu-minify@4.12.0", "", { "dependencies": { "@formatjs/icu-messageformat-parser": "^3.4.0" } }, "sha512-zDmM05uav3t3+kxSfRrNlmyXOdj2b+uHA+p04CG32eJabtaHbugXujuL+YfRkwP9joAnf0Uh+RMGCKD5NLa5rQ=="], "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], @@ -893,29 +897,29 @@ "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], - "lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="], + "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], - "lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="], + "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="], - "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA=="], + "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.32.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ=="], - "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ=="], + "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.32.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w=="], - "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA=="], + "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.32.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig=="], - "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.2", "", { "os": "linux", "cpu": "arm" }, "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA=="], + "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.32.0", "", { "os": "linux", "cpu": "arm" }, "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw=="], - "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A=="], + "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ=="], - "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA=="], + "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg=="], - "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w=="], + "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA=="], - "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA=="], + "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg=="], - "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ=="], + "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.32.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw=="], - "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="], + "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="], "lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="], @@ -931,7 +935,7 @@ "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], - "lru-cache": ["lru-cache@11.2.5", "", {}, "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw=="], + "lru-cache": ["lru-cache@11.3.6", "", {}, "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A=="], "lucide-react": ["lucide-react@0.563.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-8dXPB2GI4dI8jV4MgUDGBeLdGk8ekfqVZ0BdLcrRzocGgG75ltNEmWS+gE7uokKF/0oSUuczNDT+g9hFJ23FkA=="], @@ -951,13 +955,13 @@ "mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="], - "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + "minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], - "motion-dom": ["motion-dom@12.29.2", "", { "dependencies": { "motion-utils": "^12.29.2" } }, "sha512-/k+NuycVV8pykxyiTCoFzIVLA95Nb1BFIVvfSu9L50/6K6qNeAYtkxXILy/LRutt7AzaYDc2myj0wkCVVYAPPA=="], + "motion-dom": ["motion-dom@12.38.0", "", { "dependencies": { "motion-utils": "^12.36.0" } }, "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA=="], - "motion-utils": ["motion-utils@12.29.2", "", {}, "sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A=="], + "motion-utils": ["motion-utils@12.36.0", "", {}, "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg=="], "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], @@ -973,9 +977,9 @@ "next": ["next@16.1.6", "", { "dependencies": { "@next/env": "16.1.6", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.8.3", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.1.6", "@next/swc-darwin-x64": "16.1.6", "@next/swc-linux-arm64-gnu": "16.1.6", "@next/swc-linux-arm64-musl": "16.1.6", "@next/swc-linux-x64-gnu": "16.1.6", "@next/swc-linux-x64-musl": "16.1.6", "@next/swc-win32-arm64-msvc": "16.1.6", "@next/swc-win32-x64-msvc": "16.1.6", "sharp": "^0.34.4" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw=="], - "next-intl": ["next-intl@4.8.2", "", { "dependencies": { "@formatjs/intl-localematcher": "^0.5.4", "@parcel/watcher": "^2.4.1", "@swc/core": "^1.15.2", "icu-minify": "^4.8.2", "negotiator": "^1.0.0", "next-intl-swc-plugin-extractor": "^4.8.2", "po-parser": "^2.1.1", "use-intl": "^4.8.2" }, "peerDependencies": { "next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0", "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-GuuwyvyEI49/oehQbBXEoY8KSIYCzmfMLhmIwhMXTb+yeBmly1PnJcpgph3KczQ+HTJMXwXCmkizgtT8jBMf3A=="], + "next-intl": ["next-intl@4.12.0", "", { "dependencies": { "@formatjs/intl-localematcher": "^0.8.1", "@parcel/watcher": "^2.4.1", "@swc/core": "^1.15.2", "icu-minify": "^4.12.0", "negotiator": "^1.0.0", "next-intl-swc-plugin-extractor": "^4.12.0", "po-parser": "^2.1.1", "use-intl": "^4.12.0" }, "peerDependencies": { "next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0", "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-v8KpppWG0yLLlChJ3Of6uoPew9LeRDBAtY6vpJmF7YJmBZlHEzzoEL4w1g1dAU+VleEPNoXNm9hg1eEsKWV5hw=="], - "next-intl-swc-plugin-extractor": ["next-intl-swc-plugin-extractor@4.8.2", "", {}, "sha512-sHDs36L1VZmFHj3tPHsD+KZJtnsRudHlNvT0ieIe3iFVn5OpGLTxW3d/Zc/2LXSj5GpGuR6wQeikbhFjU9tMQQ=="], + "next-intl-swc-plugin-extractor": ["next-intl-swc-plugin-extractor@4.12.0", "", {}, "sha512-jUxVEu1Nryjt4YgaDktSys7ioOgQfcNPF/SF2dbPNxbVb6U+P1INRgHeCVN+EC59H2rnTFIQwbddmOCrUWFr3g=="], "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], @@ -1029,7 +1033,7 @@ "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], - "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], + "postcss": ["postcss@8.5.14", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg=="], "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], @@ -1041,7 +1045,7 @@ "prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], - "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], + "proxy-from-env": ["proxy-from-env@2.1.0", "", {}, "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA=="], "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], @@ -1057,7 +1061,7 @@ "react-simple-code-editor": ["react-simple-code-editor@0.14.1", "", { "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-BR5DtNRy+AswWJECyA17qhUDvrrCZ6zXOCfkQY5zSmb96BVUbpVAv03WpcjcwtCwiLbIANx3gebHOcXYn1EHow=="], - "react-toastify": ["react-toastify@11.0.5", "", { "dependencies": { "clsx": "^2.1.1" }, "peerDependencies": { "react": "^18 || ^19", "react-dom": "^18 || ^19" } }, "sha512-EpqHBGvnSTtHYhCPLxML05NLY2ZX0JURbAdNYa6BUkk+amz4wbKBQvoKQAB0ardvSarUBuY4Q4s1sluAzZwkmA=="], + "react-toastify": ["react-toastify@11.1.0", "", { "dependencies": { "clsx": "^2.1.1" }, "peerDependencies": { "react": "^18 || ^19", "react-dom": "^18 || ^19" } }, "sha512-e9h23x3phN0wbFeB6yovmWp7lobzV4CaCH0LO8nVP6H7Y+3GbcLpIzMm9dJhcp1RXbpyfvjgpfXqO80QAmn7sg=="], "react-transition-group": ["react-transition-group@4.4.5", "", { "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", "loose-envify": "^1.4.0", "prop-types": "^15.6.2" }, "peerDependencies": { "react": ">=16.6.0", "react-dom": ">=16.6.0" } }, "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g=="], @@ -1161,9 +1165,9 @@ "tailwind-scrollbar": ["tailwind-scrollbar@4.0.2", "", { "dependencies": { "prism-react-renderer": "^2.4.1" }, "peerDependencies": { "tailwindcss": "4.x" } }, "sha512-wAQiIxAPqk0MNTPptVe/xoyWi27y+NRGnTwvn4PQnbvB9kp8QUBiGl/wsfoVBHnQxTmhXJSNt9NHTmcz9EivFA=="], - "tailwindcss": ["tailwindcss@4.1.18", "", {}, "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw=="], + "tailwindcss": ["tailwindcss@4.3.0", "", {}, "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q=="], - "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="], + "tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="], "text-camel-case": ["text-camel-case@1.2.10", "", { "dependencies": { "text-pascal-case": "1.2.10" } }, "sha512-KNrWeZzQT+gh73V1LnmgTkjK7V+tMRjLCc6VrGwkqbiRdnGVIWBUgIvVnvnaVCxIvZ/2Ke8DCmgPirlQcCqD3Q=="], @@ -1243,7 +1247,7 @@ "unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="], - "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + "undici-types": ["undici-types@7.24.6", "", {}, "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg=="], "unrs-resolver": ["unrs-resolver@1.11.1", "", { "dependencies": { "napi-postinstall": "^0.3.0" }, "optionalDependencies": { "@unrs/resolver-binding-android-arm-eabi": "1.11.1", "@unrs/resolver-binding-android-arm64": "1.11.1", "@unrs/resolver-binding-darwin-arm64": "1.11.1", "@unrs/resolver-binding-darwin-x64": "1.11.1", "@unrs/resolver-binding-freebsd-x64": "1.11.1", "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-musl": "1.11.1", "@unrs/resolver-binding-wasm32-wasi": "1.11.1", "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" } }, "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg=="], @@ -1251,7 +1255,7 @@ "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], - "use-intl": ["use-intl@4.8.2", "", { "dependencies": { "@formatjs/fast-memoize": "^3.1.0", "@schummar/icu-type-parser": "1.21.5", "icu-minify": "^4.8.2", "intl-messageformat": "^11.1.0" }, "peerDependencies": { "react": "^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" } }, "sha512-3VNXZgDnPFqhIYosQ9W1Hc6K5q+ZelMfawNbexdwL/dY7BTHbceLUBX5Eeex9lgogxTp0pf1SjHuhYNAjr9H3g=="], + "use-intl": ["use-intl@4.12.0", "", { "dependencies": { "@formatjs/fast-memoize": "^3.1.0", "@schummar/icu-type-parser": "1.21.5", "icu-minify": "^4.12.0", "intl-messageformat": "^11.1.0" }, "peerDependencies": { "react": "^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" } }, "sha512-r+qVb7UI1+kiOhjYsmsNUCY+jrnjVopwGeFlmMyQj4YInlwZzgMeMSv9n8MqnWWy77HL5BVM8K2WgX50SbtcpA=="], "use-isomorphic-layout-effect": ["use-isomorphic-layout-effect@1.2.1", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA=="], @@ -1285,11 +1289,11 @@ "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], - "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], + "zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="], "zod-validation-error": ["zod-validation-error@4.0.2", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ=="], - "zustand": ["zustand@5.0.11", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg=="], + "zustand": ["zustand@5.0.13", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-efI2tVaVQPqtOh114loML/Z80Y4NP3yc+Ff0fYiZJPauNeWZeIp/bRFD7I9bfmCOYBh/PHxlglQ9+wvlwnPikQ=="], "@babel/core/json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], @@ -1305,19 +1309,25 @@ "@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], + "@formatjs/ecma402-abstract/@formatjs/fast-memoize": ["@formatjs/fast-memoize@3.1.0", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-b5mvSWCI+XVKiz5WhnBCY3RJ4ZwfjAidU0yVlKa3d3MSgKmH1hC3tBGEAtYyN5mqL7N0G5x0BOUYyO8CEupWgg=="], + "@formatjs/ecma402-abstract/@formatjs/intl-localematcher": ["@formatjs/intl-localematcher@0.8.0", "", { "dependencies": { "@formatjs/fast-memoize": "3.1.0", "tslib": "^2.8.1" } }, "sha512-zgMYWdUlmEZpX2Io+v3LHrfq9xZ6khpQVf9UAw2xYWhGerGgI9XgH1HvL/A34jWiruUJpYlP5pk4g8nIcaDrXQ=="], + "@jest/pattern/@types/node": ["@types/node@25.1.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA=="], + + "@jest/types/@types/node": ["@types/node@25.1.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA=="], + "@oclif/core/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], "@oclif/core/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], - "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" }, "bundled": true }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="], - "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="], - "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="], - "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" }, "bundled": true }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="], + "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" }, "bundled": true }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="], "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], @@ -1327,6 +1337,8 @@ "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "browserslist/baseline-browser-mapping": ["baseline-browser-mapping@2.9.19", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg=="], + "chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "cli-truncate/string-width": ["string-width@8.1.1", "", { "dependencies": { "get-east-asian-width": "^1.3.0", "strip-ansi": "^7.1.0" } }, "sha512-KpqHIdDL9KwYk22wEOg/VIqYbrnLeSApsKT/bSj6Ez7pn3CftUiLAv2Lccpq1ALcpLV9UX1Ppn92npZWu2w/aw=="], @@ -1337,20 +1349,34 @@ "eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], + "eslint-plugin-import/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + "eslint-plugin-import/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "eslint-plugin-jsx-a11y/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + + "eslint-plugin-react/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + "eslint-plugin-react/resolve": ["resolve@2.0.0-next.5", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA=="], "eslint-plugin-react/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "eslint-plugin-react-hooks/zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], + "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "filelist/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="], "hoist-non-react-statics/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + "intl-messageformat/@formatjs/fast-memoize": ["@formatjs/fast-memoize@3.1.0", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-b5mvSWCI+XVKiz5WhnBCY3RJ4ZwfjAidU0yVlKa3d3MSgKmH1hC3tBGEAtYyN5mqL7N0G5x0BOUYyO8CEupWgg=="], + "jest-message-util/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], + "jest-mock/@types/node": ["@types/node@25.1.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA=="], + + "jest-util/@types/node": ["@types/node@25.1.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA=="], + "listr2/wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="], "log-update/ansi-escapes": ["ansi-escapes@7.2.0", "", { "dependencies": { "environment": "^1.0.0" } }, "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw=="], @@ -1361,6 +1387,8 @@ "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "next/baseline-browser-mapping": ["baseline-browser-mapping@2.9.19", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg=="], + "next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], "prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], @@ -1373,10 +1401,16 @@ "string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "ts-to-zod/zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], + "tsutils/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], "wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + "@jest/pattern/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "@jest/types/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + "@oclif/core/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], @@ -1385,6 +1419,10 @@ "filelist/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + "jest-mock/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "jest-util/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + "listr2/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], "listr2/wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], diff --git a/data/as.json.br b/data/as.json.br index 5fcdff7..d749a79 100644 Binary files a/data/as.json.br and b/data/as.json.br differ diff --git a/data/avatar.json.br b/data/avatar.json.br index 76d8aac..b4374d1 100644 Binary files a/data/avatar.json.br and b/data/avatar.json.br differ diff --git a/data/changelog.json b/data/changelog.json index cc3ac91..ad42486 100644 --- a/data/changelog.json +++ b/data/changelog.json @@ -1,4 +1,12 @@ [ + { + "version": "4.2.5", + "date": "01/05/2026", + "type": "update", + "items": [ + "New data for 4.2.5" + ] + }, { "version": "4.1.6", "date": "12/04/2026", diff --git a/data/lightcone.json.br b/data/lightcone.json.br index d167301..7d08e39 100644 Binary files a/data/lightcone.json.br and b/data/lightcone.json.br differ diff --git a/data/metadata.json.br b/data/metadata.json.br index afe3236..5f55f90 100644 Binary files a/data/metadata.json.br and b/data/metadata.json.br differ diff --git a/data/moc.json.br b/data/moc.json.br index 560cf0d..bd2389c 100644 Binary files a/data/moc.json.br and b/data/moc.json.br differ diff --git a/data/monster.json.br b/data/monster.json.br index 5cf9b01..de75de6 100644 Binary files a/data/monster.json.br and b/data/monster.json.br differ diff --git a/data/peak.json.br b/data/peak.json.br index 14b0909..1ec6c45 100644 Binary files a/data/peak.json.br and b/data/peak.json.br differ diff --git a/data/pf.json.br b/data/pf.json.br index b4fa767..714e9f5 100644 Binary files a/data/pf.json.br and b/data/pf.json.br differ diff --git a/data/relic.json.br b/data/relic.json.br index 3ddb0df..19d4a63 100644 Binary files a/data/relic.json.br and b/data/relic.json.br differ diff --git a/docker-compose.yml b/docker-compose.yml index 8d37027..d24db9f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,15 +1,15 @@ services: - srtools-live: + srtools: build: context: . dockerfile: Dockerfile - container_name: srtools-live + container_name: srtools restart: unless-stopped ports: - - "3009:3000" + - "3006:3000" networks: - - srtools-live-network + - srtools-network networks: - srtools-live-network: + srtools-network: driver: bridge diff --git a/eslint.config.mjs b/eslint.config.mjs index 3fc8cde..4e2cf76 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,13 +1,15 @@ import nextCoreWebVitals from "eslint-config-next/core-web-vitals"; import nextTypescript from "eslint-config-next/typescript"; -import { dirname } from "path"; -import { fileURLToPath } from "url"; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); const eslintConfig = [...nextCoreWebVitals, ...nextTypescript, { - ignores: ["node_modules/**", ".next/**", "out/**", "build/**", "next-env.d.ts"] + ignores: [ + "node_modules/**", + ".next/**", + ".history/**", + "out/**", + "build/**", + "next-env.d.ts", + ] }]; export default eslintConfig; diff --git a/i18n/request.ts b/i18n/request.ts index bb494e3..eb91bbd 100644 --- a/i18n/request.ts +++ b/i18n/request.ts @@ -1,11 +1,27 @@ import { getRequestConfig } from "next-intl/server"; import { cookies } from "next/headers"; +const supportedLocales = new Set([ + "en", + "vi", + "ja", + "ko", + "zh", + "de", + "es", + "fr", + "id", + "pt", + "ru", + "th", +]); + export default getRequestConfig( async () => { - const locale = (await cookies()).get("MYNEXTAPP_LOCALE")?.value || "en"; + const cookieLocale = (await cookies()).get("MYNEXTAPP_LOCALE")?.value; + const locale = cookieLocale && supportedLocales.has(cookieLocale) ? cookieLocale : "en"; return { locale, messages: (await import(`../messages/${locale}.json`)).default } -}) \ No newline at end of file +}) diff --git a/messages/de.json b/messages/de.json index 871d1aa..d857abb 100644 --- a/messages/de.json +++ b/messages/de.json @@ -189,6 +189,12 @@ "useTurbulenceBuff": "Turbulenz-Buff verwenden?", "firstHalfEnemies": "Gegner erste Hälfte", "secondHalfEnemies": "Gegner zweite Hälfte", + "firstNodeEnemies": "Gegner Knoten 1", + "secondNodeEnemies": "Gegner Knoten 2", + "thirdNodeEnemies": "Gegner Knoten 3", + "firstNode": "Knoten 1", + "secondNode": "Knoten 2", + "thirdNode": "Knoten 3", "listEnemies": "Gegnerliste", "turbulenceBuff": "Turbulenz-Buff", "noEventSelected": "Kein Ereignis ausgewählt", diff --git a/messages/en.json b/messages/en.json index bba291a..59cecb8 100644 --- a/messages/en.json +++ b/messages/en.json @@ -189,6 +189,12 @@ "useTurbulenceBuff": "Use turbulence buff?", "firstHalfEnemies": "First half enemies", "secondHalfEnemies": "Second half enemies", + "firstNodeEnemies": "First node enemies", + "secondNodeEnemies": "Second node enemies", + "thirdNodeEnemies": "Third node enemies", + "firstNode": "First Node", + "secondNode": "Second Node", + "thirdNode": "Third Node", "listEnemies": "List enemies", "turbulenceBuff": "Turbulence Buff", "noEventSelected": "No event selected", diff --git a/messages/es.json b/messages/es.json index 5157145..4d1560e 100644 --- a/messages/es.json +++ b/messages/es.json @@ -189,6 +189,12 @@ "useTurbulenceBuff": "¿Usar buff de turbulencia?", "firstHalfEnemies": "Enemigos primera mitad", "secondHalfEnemies": "Enemigos segunda mitad", + "firstNodeEnemies": "Enemigos del nodo 1", + "secondNodeEnemies": "Enemigos del nodo 2", + "thirdNodeEnemies": "Enemigos del nodo 3", + "firstNode": "Nodo 1", + "secondNode": "Nodo 2", + "thirdNode": "Nodo 3", "listEnemies": "Lista de enemigos", "turbulenceBuff": "Buff de Turbulencia", "noEventSelected": "Ningún evento seleccionado", diff --git a/messages/fr.json b/messages/fr.json index d71e356..cbb21ae 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -189,6 +189,12 @@ "useTurbulenceBuff": "Utiliser le buff de turbulence ?", "firstHalfEnemies": "Ennemis première moitié", "secondHalfEnemies": "Ennemis deuxième moitié", + "firstNodeEnemies": "Ennemis du nœud 1", + "secondNodeEnemies": "Ennemis du nœud 2", + "thirdNodeEnemies": "Ennemis du nœud 3", + "firstNode": "Nœud 1", + "secondNode": "Nœud 2", + "thirdNode": "Nœud 3", "listEnemies": "Liste des ennemis", "turbulenceBuff": "Buff de Turbulence", "noEventSelected": "Aucun événement sélectionné", diff --git a/messages/id.json b/messages/id.json index 13b56d8..a1d3949 100644 --- a/messages/id.json +++ b/messages/id.json @@ -189,6 +189,12 @@ "useTurbulenceBuff": "Gunakan buff turbulence?", "firstHalfEnemies": "Musuh paruh pertama", "secondHalfEnemies": "Musuh paruh kedua", + "firstNodeEnemies": "Musuh Node 1", + "secondNodeEnemies": "Musuh Node 2", + "thirdNodeEnemies": "Musuh Node 3", + "firstNode": "Node 1", + "secondNode": "Node 2", + "thirdNode": "Node 3", "listEnemies": "Daftar musuh", "turbulenceBuff": "Turbulence Buff", "noEventSelected": "Tidak ada event dipilih", diff --git a/messages/ja.json b/messages/ja.json index de6ef5c..8f0e6e0 100644 --- a/messages/ja.json +++ b/messages/ja.json @@ -189,6 +189,12 @@ "useTurbulenceBuff": "乱気流バフを使用しますか?", "firstHalfEnemies": "前半の敵", "secondHalfEnemies": "後半の敵", + "firstNodeEnemies": "ノード 1 の敵", + "secondNodeEnemies": "ノード 2 の敵", + "thirdNodeEnemies": "ノード 3 の敵", + "firstNode": "ノード 1", + "secondNode": "ノード 2", + "thirdNode": "ノード 3", "turbulenceBuff": "乱気流バフ", "noEventSelected": "イベントが選択されていません", "noTurbulenceBuff": "乱気流バフがありません", diff --git a/messages/ko.json b/messages/ko.json index 5868708..dad78ae 100644 --- a/messages/ko.json +++ b/messages/ko.json @@ -189,6 +189,12 @@ "useTurbulenceBuff": "난류 버프 사용?", "firstHalfEnemies": "전반 적", "secondHalfEnemies": "후반 적", + "firstNodeEnemies": "노드 1 적", + "secondNodeEnemies": "노드 2 적", + "thirdNodeEnemies": "노드 3 적", + "firstNode": "노드 1", + "secondNode": "노드 2", + "thirdNode": "노드 3", "turbulenceBuff": "난류 버프", "noEventSelected": "이벤트가 선택되지 않음", "noTurbulenceBuff": "난류 버프가 없음", diff --git a/messages/pt.json b/messages/pt.json index a333a4a..d925603 100644 --- a/messages/pt.json +++ b/messages/pt.json @@ -189,6 +189,12 @@ "useTurbulenceBuff": "Usar buff de turbulência?", "firstHalfEnemies": "Inimigos da primeira metade", "secondHalfEnemies": "Inimigos da segunda metade", + "firstNodeEnemies": "Inimigos do nodo 1", + "secondNodeEnemies": "Inimigos do nodo 2", + "thirdNodeEnemies": "Inimigos do nodo 3", + "firstNode": "Nodo 1", + "secondNode": "Nodo 2", + "thirdNode": "Nodo 3", "listEnemies": "Lista de inimigos", "turbulenceBuff": "Buff de Turbulência", "noEventSelected": "Nenhum evento selecionado", diff --git a/messages/ru.json b/messages/ru.json index d0f9603..5dd699b 100644 --- a/messages/ru.json +++ b/messages/ru.json @@ -189,6 +189,12 @@ "useTurbulenceBuff": "Использовать бафф турбулентности?", "firstHalfEnemies": "Враги первой половины", "secondHalfEnemies": "Враги второй половины", + "firstNodeEnemies": "Враги узла 1", + "secondNodeEnemies": "Враги узла 2", + "thirdNodeEnemies": "Враги узла 3", + "firstNode": "Узел 1", + "secondNode": "Узел 2", + "thirdNode": "Узел 3", "listEnemies": "Список врагов", "turbulenceBuff": "Бафф турбулентности", "noEventSelected": "Событие не выбрано", diff --git a/messages/th.json b/messages/th.json index 96aca71..b59f57b 100644 --- a/messages/th.json +++ b/messages/th.json @@ -189,6 +189,12 @@ "useTurbulenceBuff": "ใช้บัฟบรรยากาศหรือไม่?", "firstHalfEnemies": "ศัตรูครึ่งแรก", "secondHalfEnemies": "ศัตรูครึ่งหลัง", + "firstNodeEnemies": "ศัตรูโหนด 1", + "secondNodeEnemies": "ศัตรูโหนด 2", + "thirdNodeEnemies": "ศัตรูโหนด 3", + "firstNode": "โหนด 1", + "secondNode": "โหนด 2", + "thirdNode": "โหนด 3", "listEnemies": "รายการศัตรู", "turbulenceBuff": "บัฟบรรยากาศ", "noEventSelected": "ไม่ได้เลือกอีเวนต์", diff --git a/messages/vi.json b/messages/vi.json index 42f0ddf..073e6d2 100644 --- a/messages/vi.json +++ b/messages/vi.json @@ -189,6 +189,12 @@ "useTurbulenceBuff": "Dùng buff hỗn loạn?", "firstHalfEnemies": "Địch nửa đầu", "secondHalfEnemies": "Địch nửa sau", + "firstNodeEnemies": "Địch Node 1", + "secondNodeEnemies": "Địch Node 2", + "thirdNodeEnemies": "Địch Node 3", + "firstNode": "Node 1", + "secondNode": "Node 2", + "thirdNode": "Node 3", "turbulenceBuff": "Buff hỗn loạn", "noEventSelected": "Không có sự kiện", "noTurbulenceBuff": "Không có buff hỗn loạn", diff --git a/messages/zh.json b/messages/zh.json index 6cbbacf..c399868 100644 --- a/messages/zh.json +++ b/messages/zh.json @@ -189,6 +189,12 @@ "useTurbulenceBuff": "使用记忆紊流?", "firstHalfEnemies": "上半场敌人", "secondHalfEnemies": "下半场敌人", + "firstNodeEnemies": "节点 1 敌人", + "secondNodeEnemies": "节点 2 敌人", + "thirdNodeEnemies": "节点 3 敌人", + "firstNode": "节点 1", + "secondNode": "节点 2", + "thirdNode": "节点 3", "turbulenceBuff": "增益效果", "noEventSelected": "未选择事件", "noTurbulenceBuff": "未选择增益效果", diff --git a/package.json b/package.json index dfcd7d4..cb043d9 100644 --- a/package.json +++ b/package.json @@ -10,37 +10,37 @@ }, "dependencies": { "@next/bundle-analyzer": "16.1.6", - "@tanstack/react-query": "^5.90.20", - "axios": "^1.13.4", - "fast-average-color": "^9.5.0", - "framer-motion": "^12.29.2", - "html2canvas-pro": "^1.6.6", - "lru-cache": "^11.2.5", + "@tanstack/react-query": "^5.100.10", + "axios": "^1.16.1", + "fast-average-color": "^9.5.2", + "framer-motion": "^12.38.0", + "html2canvas-pro": "^1.6.7", + "lru-cache": "^11.3.6", "lucide-react": "^0.563.0", "next": "16.1.6", - "next-intl": "^4.8.2", + "next-intl": "^4.12.0", "prismjs": "^1.30.0", "react": "19.2.4", "react-dom": "19.2.4", "react-select": "^5.10.2", "react-simple-code-editor": "^0.14.1", - "react-toastify": "^11.0.5", + "react-toastify": "^11.1.0", "sharp": "^0.34.5", - "zod": "^4.3.6", - "zustand": "^5.0.11" + "zod": "^4.4.3", + "zustand": "^5.0.13" }, "devDependencies": { - "@tailwindcss/postcss": "^4.1.18", + "@tailwindcss/postcss": "^4.3.0", "@types/jest": "^30.0.0", - "@types/node": "^25.1.0", + "@types/node": "^25.8.0", "@types/react": "19.2.6", "@types/react-dom": "19.2.3", - "baseline-browser-mapping": "^2.9.19", - "daisyui": "^5.5.14", - "eslint": "^9.39.2", + "baseline-browser-mapping": "^2.10.29", + "daisyui": "^5.5.19", + "eslint": "^9.39.4", "eslint-config-next": "16.1.6", "tailwind-scrollbar": "^4.0.2", - "tailwindcss": "^4.1.18", + "tailwindcss": "^4.3.0", "ts-to-zod": "^5.1.0", "typescript": "^5.9.3" }, diff --git a/src/components/header/index.tsx b/src/components/header/index.tsx index a7107cc..1e69938 100644 --- a/src/components/header/index.tsx +++ b/src/components/header/index.tsx @@ -79,6 +79,8 @@ export default function Header() { if (cookieLocale) { if (!listCurrentLanguageApi.hasOwnProperty(cookieLocale)) { setLocale("en") + document.cookie = "MYNEXTAPP_LOCALE=en;" + router.refresh() } else { setLocale(cookieLocale) } @@ -614,4 +616,4 @@ export default function Header() { ))} ) -} \ No newline at end of file +} diff --git a/src/components/importBar/copy.tsx b/src/components/importBar/copy.tsx index 0dff700..8b4455a 100644 --- a/src/components/importBar/copy.tsx +++ b/src/components/importBar/copy.tsx @@ -71,8 +71,11 @@ export default function CopyImport() { const selectAll = () => { if (avatarCopySelected) { - setSelectedProfiles(avatars[avatarCopySelected?.ID.toString()].profileList.map((profile, index) => { - if (!profile.lightcone?.item_id && Object.keys(profile.relics).length == 0) { + const sourceAvatar = avatars[avatarCopySelected.ID.toString()] + const sourceProfiles = sourceAvatar?.profileList ?? [] + + setSelectedProfiles(sourceProfiles.map((profile, index) => { + if (!profile.lightcone?.item_id && Object.keys(profile.relics ?? {}).length == 0) { return null; } return { @@ -110,8 +113,20 @@ export default function CopyImport() { return; } - const newListProfile = avatars[avatarCopySelected.ID.toString()].profileList.map((profile) => { - if (!profile.lightcone?.item_id && Object.keys(profile.relics).length == 0) { + const sourceAvatar = avatars[avatarCopySelected.ID.toString()] + const targetAvatar = avatars[avatarSelected.ID.toString()] + + if (!sourceAvatar || !targetAvatar) { + setMessage({ + type: "error", + text: transI18n("noDataToImport") + }); + return; + } + + const selectedKeys = new Set(selectedProfiles.map((profile) => profile.key)) + const newListProfile = sourceAvatar.profileList.map((profile, index) => { + if (!selectedKeys.has(index) || (!profile.lightcone?.item_id && Object.keys(profile.relics ?? {}).length == 0)) { return null; } return { @@ -121,9 +136,9 @@ export default function CopyImport() { }).filter((profile) => profile !== null); const newAvatar = { - ...avatars[avatarSelected?.ID?.toString()], - profileList: avatars[avatarSelected?.ID?.toString()].profileList.concat(newListProfile), - profileSelect: avatars[avatarSelected?.ID?.toString()].profileList.length - 1, + ...targetAvatar, + profileList: targetAvatar.profileList.concat(newListProfile), + profileSelect: targetAvatar.profileList.length + newListProfile.length - 1, } setAvatar(newAvatar); setSelectedProfiles([]); @@ -275,7 +290,7 @@ export default function CopyImport() { {/* Character Grid */}
{avatarCopySelected && avatars[avatarCopySelected?.ID.toString()]?.profileList.map((profile, index) => { - if (!profile.lightcone?.item_id && Object.keys(profile.relics).length == 0) { + if (!profile.lightcone?.item_id && Object.keys(profile.relics ?? {}).length == 0) { return null; } return ( @@ -291,4 +306,4 @@ export default function CopyImport() {
) -} \ No newline at end of file +} diff --git a/src/components/importBar/enka.tsx b/src/components/importBar/enka.tsx index 138a0df..b567f61 100644 --- a/src/components/importBar/enka.tsx +++ b/src/components/importBar/enka.tsx @@ -9,6 +9,28 @@ import { converterOneEnkaDataToAvatarStore } from "@/helper"; import useModelStore from "@/stores/modelStore"; import { toast } from "react-toastify"; import { useTranslations } from "next-intl"; +import { avatarEnkaDetailSchema, enkaResponseSchema } from "@/zod"; +import { z } from "zod"; +import useDetailDataStore from "@/stores/detailDataStore"; + +type AvatarEnkaDetailInput = z.infer; + +const toCharacterInfoCard = (character: AvatarEnkaDetailInput): CharacterInfoCardType => ({ + key: character.avatarId, + avatar_id: character.avatarId, + rank: character.rank ?? 0, + level: character.level, + lightcone: { + level: character.equipment?.level ?? 0, + rank: character.equipment?.rank ?? 0, + item_id: character.equipment?.tid ?? 0, + }, + relics: character.relicList.map((relic) => ({ + level: relic.level, + relic_id: relic.tid, + relic_set_id: parseInt(relic.tid.toString().slice(1, -1), 10), + })), +}); export default function EnkaImport() { const { @@ -22,8 +44,10 @@ export default function EnkaImport() { const transI18n = useTranslations("DataPage") const { avatars, setAvatar } = useUserDataStore(); const { setIsOpenImport } = useModelStore() + const { mapAvatar } = useDetailDataStore() const [isLoading, setIsLoading] = useState(false) const [Error, setError] = useState("") + const validCharacters = enkaData?.detailInfo.avatarDetailList.filter((character) => mapAvatar?.[character.avatarId]) ?? [] const handlerFetchData = async () => { if (!uidInput) { @@ -31,32 +55,27 @@ export default function EnkaImport() { return; } setIsLoading(true) - const data : EnkaResponse = await SendDataThroughProxy({data: {serverUrl: "https://enka.network/api/hsr/uid/" + uidInput, method: "GET"}}) - if (data) { - setEnkaData(data) - setSelectedCharacters(data.detailInfo.avatarDetailList.map((character) => { - return { - key: character.avatarId, - avatar_id: character.avatarId, - rank: character.rank ?? 0, - level: character.level, - lightcone: { - level: character.equipment?.level ?? 0, - rank: character.equipment?.rank ?? 0, - item_id: character.equipment?.tid ?? 0, - }, - relics: character.relicList.map((relic) => ({ - level: relic.level, - relic_id: relic.tid, - relic_set_id: parseInt(relic.tid.toString().slice(1, -1), 10), - })), - } as CharacterInfoCardType - })) + try { + const data: unknown = await SendDataThroughProxy({data: {serverUrl: "https://enka.network/api/hsr/uid/" + uidInput, method: "GET"}}) + const parsed = enkaResponseSchema.safeParse(data) + + if (!parsed.success) { + setEnkaData(null) + setSelectedCharacters([]) + setError(transI18n("failedToFetchEnkaData")) + return + } + + setEnkaData(parsed.data as EnkaResponse) + setSelectedCharacters(parsed.data.detailInfo.avatarDetailList.filter((character) => mapAvatar?.[character.avatarId]).map(toCharacterInfoCard)) setError("") - } else { + } catch { + setEnkaData(null) + setSelectedCharacters([]) setError(transI18n("failedToFetchEnkaData")) + } finally { + setIsLoading(false) } - setIsLoading(false) } const handleCharacterToggle = (character: CharacterInfoCardType) => { @@ -73,26 +92,7 @@ export default function EnkaImport() { const selectAll = () => { if (enkaData) { - setSelectedCharacters(enkaData?.detailInfo.avatarDetailList.map((character) => { - return { - key: character.avatarId, - avatar_id: character.avatarId, - rank: character.rank ?? 0, - level: character.level, - lightcone: (character.equipment && character.equipment.tid) ? { - level: character.equipment?.level ?? 0, - rank: character.equipment?.rank ?? 0, - item_id: character.equipment?.tid ?? 0, - } : null, - relics: character.relicList.map((relic) => { - return { - level: relic.level, - relic_id: relic.tid, - relic_set_id: parseInt(relic.tid.toString().slice(1, -1), 10), - } - }), - } as CharacterInfoCardType - })); + setSelectedCharacters(validCharacters.map(toCharacterInfoCard)); } }; @@ -107,7 +107,13 @@ export default function EnkaImport() { } setError(""); const listAvatars = { ...avatars } - const filterData = enkaData.detailInfo.avatarDetailList.filter((character) => selectedCharacters.some((selectedCharacter) => selectedCharacter.avatar_id === character.avatarId)) + const parsed = enkaResponseSchema.safeParse(enkaData) + if (!parsed.success) { + setError(transI18n("failedToFetchEnkaData")); + return; + } + + const filterData = parsed.data.detailInfo.avatarDetailList.filter((character) => mapAvatar?.[character.avatarId] && selectedCharacters.some((selectedCharacter) => selectedCharacter.avatar_id === character.avatarId)) filterData.forEach((character) => { const newAvatar = { ...listAvatars[character.avatarId.toString()] } if (Object.keys(newAvatar).length !== 0) { @@ -193,26 +199,10 @@ export default function EnkaImport() { )} {/* Character Grid */}
- {enkaData?.detailInfo.avatarDetailList.map((character) => ( + {validCharacters.map((character) => ( ({ - level: relic.level ?? 0, - relic_id: relic.tid, - relic_set_id: parseInt(relic.tid.toString().slice(1, -1), 10), - })), - } as CharacterInfoCardType - } + character={toCharacterInfoCard(character)} selectedCharacters={selectedCharacters} onCharacterToggle={handleCharacterToggle} /> @@ -221,4 +211,4 @@ export default function EnkaImport() {
); -} \ No newline at end of file +} diff --git a/src/components/importBar/freesr.tsx b/src/components/importBar/freesr.tsx index bfc028d..e51314f 100644 --- a/src/components/importBar/freesr.tsx +++ b/src/components/importBar/freesr.tsx @@ -11,6 +11,31 @@ import { toast } from "react-toastify"; import { converterOneFreeSRDataToAvatarStore } from "@/helper"; import { useTranslations } from "next-intl"; import useDetailDataStore from "@/stores/detailDataStore"; +import { z } from "zod"; + +type FreeSRJsonInput = z.infer; + +const toCharacterInfoCard = (data: FreeSRJsonInput, character: FreeSRJsonInput["avatars"][string]): CharacterInfoCardType => { + const lightcone = data.lightcones.find((lightcone) => lightcone.equip_avatar === character.avatar_id) + const relics = data.relics.filter((relic) => relic.equip_avatar === character.avatar_id) + + return { + key: character.avatar_id, + avatar_id: character.avatar_id, + rank: character.data.rank ?? 0, + level: character.level, + lightcone: { + level: lightcone?.level ?? 0, + rank: lightcone?.rank ?? 0, + item_id: lightcone?.item_id ?? 0, + }, + relics: relics.map((relic) => ({ + level: relic.level, + relic_id: relic.relic_id, + relic_set_id: relic.relic_set_id, + })), + } +} export default function FreeSRImport() { const { avatars, setAvatar } = useUserDataStore(); @@ -20,6 +45,8 @@ export default function FreeSRImport() { const [Error, setError] = useState("") const { freeSRData, setFreeSRData, selectedCharacters, setSelectedCharacters } = useFreeSRStore() const transI18n = useTranslations("DataPage") + const parsedFreeSRData = freeSrJsonSchema.safeParse(freeSRData) + const validFreeSRData = parsedFreeSRData.success ? parsedFreeSRData.data : null const handleCharacterToggle = (character: CharacterInfoCardType) => { if (selectedCharacters.some((selectedCharacter) => selectedCharacter.key === character.key)) { @@ -34,27 +61,9 @@ export default function FreeSRImport() { }; const selectAll = () => { - if (freeSRData) { - setSelectedCharacters(Object.values(freeSRData?.avatars).filter(it => mapAvatar?.[it.avatar_id]).map((character) => { - const lightcone = freeSRData.lightcones.find((lightcone) => lightcone.equip_avatar === character.avatar_id) - const relics = freeSRData.relics.filter((relic) => relic.equip_avatar === character.avatar_id) - return { - key: character.avatar_id, - avatar_id: character.avatar_id, - rank: character.data.rank ?? 0, - level: character.level, - lightcone: { - level: lightcone?.level ?? 0, - rank: lightcone?.rank ?? 0, - item_id: lightcone?.item_id ?? "", - }, - relics: relics.map((relic) => ({ - level: relic.level, - relic_id: relic.relic_id, - relic_set_id: relic.relic_set_id, - })), - } as CharacterInfoCardType - })); + const parsed = freeSrJsonSchema.safeParse(freeSRData) + if (parsed.success) { + setSelectedCharacters(Object.values(parsed.data.avatars).filter(it => mapAvatar?.[it.avatar_id]).map((character) => toCharacterInfoCard(parsed.data, character))); } }; @@ -82,41 +91,35 @@ export default function FreeSRImport() { reader.onload = (e) => { try { const data = JSON.parse(e.target?.result as string); - const parsed = freeSrJsonSchema.parse(data) - setFreeSRData(parsed) + const parsed = freeSrJsonSchema.safeParse(data) + if (!parsed.success) { + setSelectedCharacters([]) + setFreeSRData(null) + setError(transI18n("fileMustBeAValidJsonFile")) + return + } + + setFreeSRData(parsed.data) setError("") - setSelectedCharacters(Object.values(parsed?.avatars || {}).filter(it => mapAvatar?.[it.avatar_id]).map((character) => { - const lightcone = parsed?.lightcones.find((lightcone) => lightcone.equip_avatar === character.avatar_id) - const relics = parsed?.relics.filter((relic) => relic.equip_avatar === character.avatar_id) - return { - key: character.avatar_id, - avatar_id: character.avatar_id, - rank: character.data.rank ?? 0, - level: character.level, - lightcone: { - level: lightcone?.level ?? 0, - rank: lightcone?.rank ?? 0, - item_id: lightcone?.item_id ?? "", - }, - relics: relics?.map((relic) => ({ - level: relic.level, - relic_id: relic.relic_id, - relic_set_id: relic.relic_set_id, - })) ?? [], - } as CharacterInfoCardType - })); + setSelectedCharacters(Object.values(parsed.data.avatars).filter(it => mapAvatar?.[it.avatar_id]).map((character) => toCharacterInfoCard(parsed.data, character))); } catch { setSelectedCharacters([]) setFreeSRData(null) setError(transI18n("fileMustBeAValidJsonFile")) + } finally { + setIsLoading(false) } }; + reader.onerror = () => { + setSelectedCharacters([]) + setFreeSRData(null) + setError(transI18n("fileMustBeAValidJsonFile")) + setIsLoading(false) + } reader.readAsText(file); - setIsLoading(false) } - setIsLoading(false) }; const handleImport = () => { @@ -130,8 +133,14 @@ export default function FreeSRImport() { } setError(""); + const parsed = freeSrJsonSchema.safeParse(freeSRData) + if (!parsed.success) { + setError(transI18n("fileMustBeAValidJsonFile")); + return; + } + const listAvatars = { ...avatars } - const filterData = Object.values(freeSRData?.avatars || {}).filter((character) => selectedCharacters.some((selectedCharacter) => selectedCharacter.avatar_id === character.avatar_id)) + const filterData = Object.values(parsed.data.avatars).filter((character) => selectedCharacters.some((selectedCharacter) => selectedCharacter.avatar_id === character.avatar_id)) filterData.forEach((character) => { const newAvatar = { ...listAvatars[character.avatar_id] } if (Object.keys(newAvatar).length !== 0) { @@ -141,7 +150,7 @@ export default function FreeSRImport() { rank: character.data.rank ?? 0, skills: character.data.skills } - const newProfile = converterOneFreeSRDataToAvatarStore(freeSRData, newAvatar.profileList.length, character.avatar_id) + const newProfile = converterOneFreeSRDataToAvatarStore(parsed.data, newAvatar.profileList.length, character.avatar_id) if (newProfile) { newAvatar.profileList.push(newProfile) newAvatar.profileSelect = newAvatar.profileList.length - 1 @@ -202,29 +211,11 @@ export default function FreeSRImport() { )} {/* Character Grid */}
- {Object.values(freeSRData?.avatars || {}).filter(it => mapAvatar?.[it.avatar_id]).map((character) => { - const lightcone = freeSRData?.lightcones.find((lightcone) => lightcone.equip_avatar === character.avatar_id) - const relics = freeSRData?.relics.filter((relic) => relic.equip_avatar === character.avatar_id) + {validFreeSRData && Object.values(validFreeSRData.avatars).filter(it => mapAvatar?.[it.avatar_id]).map((character) => { return ( ({ - level: relic.level, - relic_id: relic.relic_id, - relic_set_id: relic.relic_set_id, - })) ?? [], - } as CharacterInfoCardType - } + character={toCharacterInfoCard(validFreeSRData, character)} selectedCharacters={selectedCharacters} onCharacterToggle={handleCharacterToggle} /> @@ -234,4 +225,4 @@ export default function FreeSRImport() {
) -} \ No newline at end of file +} diff --git a/src/components/monsterBar/as.tsx b/src/components/monsterBar/as.tsx index 4551d98..6d799c0 100644 --- a/src/components/monsterBar/as.tsx +++ b/src/components/monsterBar/as.tsx @@ -5,7 +5,7 @@ import { calcMonsterStats, getLocaleName, replaceByParam } from "@/helper"; import useLocaleStore from "@/stores/localeStore"; import useUserDataStore from "@/stores/userDataStore"; import Image from "next/image"; -import { MonsterStore } from "@/types"; +import { ASEvent, MonsterStore } from "@/types"; import { useTranslations } from "next-intl"; import useDetailDataStore from "@/stores/detailDataStore"; @@ -16,7 +16,6 @@ export default function AsBar() { setAsConfig } = useUserDataStore() const { mapMonster, mapAS, damageType, hardLevelConfig, eliteConfig } = useDetailDataStore() - const transI18n = useTranslations("DataPage") const challengeSelected = useMemo(() => { @@ -27,20 +26,52 @@ export default function AsBar() { return mapAS[as_config.event_id.toString()] }, [as_config, mapAS]) + + const floorSideList = useMemo(() => { + if (!eventSelected) return []; + + const floorList = [ + { + id: "firstNode", + name: transI18n("firstNode"), + wave: transI18n("firstNodeEnemies") + }, + { + id: "secondNode", + name: transI18n("secondNode"), + wave: transI18n("secondNodeEnemies") + }, + + ] + + if (eventSelected?.Tierce && eventSelected.Tierce.PreChallenge === as_config.challenge_id) { + floorList.push({ + id: "thirdNode", + name: transI18n("thirdNode"), + wave: transI18n("thirdNodeEnemies") + }) + } + return floorList + }, [as_config.challenge_id, eventSelected, transI18n]) + const buffList = useMemo(() => { if (!eventSelected) return []; - if (as_config.floor_side === "Upper" || as_config.floor_side === "Upper -> Lower") { + if (as_config.floor_side === "firstNode") { return eventSelected?.BuffList1 ?? []; } - if (as_config.floor_side === "Lower" || as_config.floor_side === "Lower -> Upper") { + if (as_config.floor_side === "secondNode") { return eventSelected?.BuffList2 ?? []; } + + if (as_config.floor_side === "thirdNode" && eventSelected?.BuffList3) { + return eventSelected?.BuffList3 ?? []; + } + return []; }, [as_config.floor_side, eventSelected]); - useEffect(() => { if (!challengeSelected || as_config.event_id === 0 || as_config.challenge_id === 0) return const newBattleConfig = structuredClone(as_config) @@ -65,67 +96,36 @@ export default function AsBar() { newBattleConfig.monsters = [] newBattleConfig.stage_id = 0 - if ((as_config.floor_side === "Upper" || as_config.floor_side === "Upper -> Lower") - && challengeSelected.EventList1.length > 0) { - newBattleConfig.stage_id = challengeSelected.EventList1[0].ID - for (const wave of challengeSelected.EventList1[0].MonsterList) { + + let targetEventList: ASEvent[] = [] + if (as_config.floor_side === "firstNode" && challengeSelected.EventList1.length > 0) { + targetEventList = challengeSelected.EventList1 + } else if (as_config.floor_side === "secondNode" && challengeSelected.EventList2.length > 0) { + targetEventList = challengeSelected.EventList2 + } else if (as_config.floor_side === "thirdNode" && eventSelected?.Tierce && eventSelected.Tierce.EventList.length > 0) { + targetEventList = eventSelected.Tierce.EventList + } + + if (targetEventList.length > 0) { + newBattleConfig.stage_id = targetEventList[0].ID + for (const wave of targetEventList[0].MonsterList) { const newWave: MonsterStore[] = [] for (const value of Object.values(wave)) { newWave.push({ monster_id: value, - level: challengeSelected.EventList1[0].Level, - amount: 1, - }) - } - newBattleConfig.monsters.push(newWave) - } - } - if ((as_config.floor_side === "Lower" || as_config.floor_side === "Lower -> Upper") - && challengeSelected.EventList2.length > 0) { - newBattleConfig.stage_id = challengeSelected.EventList2[0].ID - for (const wave of challengeSelected.EventList2[0].MonsterList) { - const newWave: MonsterStore[] = [] - for (const value of Object.values(wave)) { - newWave.push({ - monster_id: value, - level: challengeSelected.EventList2[0].Level, - amount: 1, - }) - } - newBattleConfig.monsters.push(newWave) - } - } - if (as_config.floor_side === "Lower -> Upper" - && challengeSelected.EventList1.length > 0) { - for (const wave of challengeSelected.EventList1[0].MonsterList) { - const newWave: MonsterStore[] = [] - for (const value of Object.values(wave)) { - newWave.push({ - monster_id: value, - level: challengeSelected.EventList1[0].Level, - amount: 1, - }) - } - newBattleConfig.monsters.push(newWave) - } - } else if (as_config.floor_side === "Upper -> Lower" - && challengeSelected.EventList2.length > 0) { - for (const wave of challengeSelected.EventList2[0].MonsterList) { - const newWave: MonsterStore[] = [] - for (const value of Object.values(wave)) { - newWave.push({ - monster_id: value, - level: challengeSelected.EventList2[0].Level, + level: targetEventList[0].Level, amount: 1, }) } newBattleConfig.monsters.push(newWave) } } + setAsConfig(newBattleConfig) // eslint-disable-next-line react-hooks/exhaustive-deps }, [ challengeSelected, + eventSelected, mapAS, as_config.event_id, as_config.challenge_id, @@ -186,10 +186,9 @@ export default function AsBar() { onChange={(e) => setAsConfig({ ...as_config, floor_side: e.target.value })} > - - - - + {floorSideList.map((side) => { + return + })} @@ -233,182 +232,107 @@ export default function AsBar() { {/* Enemy Waves */} {(as_config?.challenge_id ?? 0) !== 0 && ( -
- {/* First Half */} -
-

{transI18n("firstHalfEnemies")}

+
+ {floorSideList.map((side, i) => { + const eventList = side.id === "firstNode" + ? challengeSelected?.EventList1 + : side.id === "secondNode" + ? challengeSelected?.EventList2 + : side.id === "thirdNode" + ? eventSelected?.Tierce?.EventList + : []; - {challengeSelected && challengeSelected?.EventList1?.length > 0 && challengeSelected?.EventList1?.[0]?.MonsterList?.map((wave, waveIndex) => ( -
-

{transI18n("wave")} {waveIndex + 1}

-
- {Object.values(wave).map((waveValue, enemyIndex) => { - const monsterStats = calcMonsterStats( - mapMonster?.[waveValue.toString()], - challengeSelected?.EventList1?.[0]?.EliteGroup, - challengeSelected?.EventList1?.[0]?.HardLevelGroup, - challengeSelected?.EventList1?.[0]?.Level, - hardLevelConfig, - eliteConfig - ); - return ( -
-
- Lv. {challengeSelected?.EventList1[0].Level} -
+ if (!eventList || eventList.length === 0) return null; + const targetEvent = eventList[0]; -
- {mapMonster?.[waveValue.toString()]?.Image?.IconPath && ( -
- Enemy Icon -
- )} -
+ return ( +
+

{side.wave}

-
-
-
- HP - {monsterStats.hp.toLocaleString(undefined, { maximumFractionDigits: 0 })} -
- -
- Speed - {monsterStats.spd.toLocaleString(undefined, { maximumFractionDigits: 0 })} -
- -
- Toughness - {monsterStats.stance.toLocaleString(undefined, { maximumFractionDigits: 0 })} -
+ {targetEvent?.MonsterList?.map((wave, waveIndex) => ( +
+

{transI18n("wave")} {waveIndex + 1}

+
+ {Object.values(wave).map((waveValue, enemyIndex) => { + const monsterStats = calcMonsterStats( + mapMonster?.[waveValue.toString()], + targetEvent?.EliteGroup, + targetEvent?.HardLevelGroup, + targetEvent?.Level, + hardLevelConfig, + eliteConfig + ); + return ( +
+
+ Lv. {targetEvent.Level}
-
- - Weakness - -
- {mapMonster?.[waveValue.toString()]?.StanceWeakList?.map((icon, iconIndex) => ( +
+ {mapMonster?.[waveValue.toString()]?.Image?.IconPath && ( +
{icon} - ))} +
+ )} +
+ +
+
+
+ HP + {monsterStats.hp.toLocaleString(undefined, { maximumFractionDigits: 0 })} +
+ +
+ Speed + {monsterStats.spd.toLocaleString(undefined, { maximumFractionDigits: 0 })} +
+ +
+ Toughness + {monsterStats.stance.toLocaleString(undefined, { maximumFractionDigits: 0 })} +
+
+ +
+ + Weakness + +
+ {mapMonster?.[waveValue.toString()]?.StanceWeakList?.map((icon, iconIndex) => ( + {icon} + ))} +
-
- ) - })} + ) + })} +
-
- ))} -
- - {/* Second Half */} -
-

{transI18n("secondHalfEnemies")}

- - {challengeSelected && challengeSelected?.EventList2?.length > 0 && challengeSelected?.EventList2?.[0]?.MonsterList?.map((wave, waveIndex) => ( -
-

{transI18n("wave")} {waveIndex + 1}

-
- {Object.values(wave).map((waveValue, enemyIndex) => { - const monsterStats = calcMonsterStats( - mapMonster?.[waveValue.toString()], - challengeSelected?.EventList2?.[0]?.EliteGroup, - challengeSelected?.EventList2?.[0]?.HardLevelGroup, - challengeSelected?.EventList2?.[0]?.Level, - hardLevelConfig, - eliteConfig - ); - return ( -
-
- Lv. {challengeSelected?.EventList2[0].Level} -
- -
- {mapMonster?.[waveValue.toString()]?.Image?.IconPath && ( -
- Enemy Icon -
- )} -
- -
-
-
- HP - {monsterStats.hp.toLocaleString(undefined, { maximumFractionDigits: 0 })} -
- -
- Speed - {monsterStats.spd.toLocaleString(undefined, { maximumFractionDigits: 0 })} -
- -
- Toughness - {monsterStats.stance.toLocaleString(undefined, { maximumFractionDigits: 0 })} -
-
- -
- - Weakness - -
- {mapMonster?.[waveValue.toString()]?.StanceWeakList?.map((icon, iconIndex) => ( - {icon} - ))} -
-
-
-
- ) - })} -
-
- ))} -
+ ))} +
+ )})}
)} diff --git a/src/components/monsterBar/moc.tsx b/src/components/monsterBar/moc.tsx index 8901555..6cfac7f 100644 --- a/src/components/monsterBar/moc.tsx +++ b/src/components/monsterBar/moc.tsx @@ -7,7 +7,7 @@ import useLocaleStore from "@/stores/localeStore"; import useUserDataStore from "@/stores/userDataStore"; import Image from "next/image"; import { useTranslations } from "next-intl"; -import { MonsterStore } from "@/types"; +import { MoCEvent, MonsterStore } from "@/types"; import useDetailDataStore from "@/stores/detailDataStore"; export default function MocBar() { @@ -28,6 +28,33 @@ export default function MocBar() { return mapMoc[moc_config.event_id.toString()] }, [moc_config, mapMoc]) + const floorSideList = useMemo(() => { + if (!eventSelected) return []; + + const floorList = [ + { + id: "firstNode", + name: transI18n("firstNode"), + wave: transI18n("firstNodeEnemies") + }, + { + id: "secondNode", + name: transI18n("secondNode"), + wave: transI18n("secondNodeEnemies") + }, + + ] + + if (eventSelected?.Tierce && eventSelected.Tierce.PreChallenge === moc_config.challenge_id) { + floorList.push({ + id: "thirdNode", + name: transI18n("thirdNode"), + wave: transI18n("thirdNodeEnemies") + }) + } + return floorList + }, [moc_config.challenge_id, eventSelected, transI18n]) + useEffect(() => { if (!challengeSelected || moc_config.event_id === 0 || moc_config.challenge_id === 0) return @@ -47,62 +74,36 @@ export default function MocBar() { } newBattleConfig.monsters = [] newBattleConfig.stage_id = 0 - if ((moc_config.floor_side === "Upper" || moc_config.floor_side === "Upper -> Lower") && challengeSelected.EventList1.length > 0) { - newBattleConfig.stage_id = challengeSelected.EventList1[0].ID - for (const wave of challengeSelected.EventList1[0].MonsterList) { + + let targetEventList: MoCEvent[] = [] + if (moc_config.floor_side === "firstNode" && challengeSelected.EventList1.length > 0) { + targetEventList = challengeSelected.EventList1 + } else if (moc_config.floor_side === "secondNode" && challengeSelected.EventList2.length > 0) { + targetEventList = challengeSelected.EventList2 + } else if (moc_config.floor_side === "thirdNode" && eventSelected?.Tierce && eventSelected.Tierce.EventList.length > 0) { + targetEventList = eventSelected.Tierce.EventList + } + + if (targetEventList.length > 0) { + newBattleConfig.stage_id = targetEventList[0].ID + for (const wave of targetEventList[0].MonsterList) { const newWave: MonsterStore[] = [] for (const value of Object.values(wave)) { newWave.push({ monster_id: value, - level: challengeSelected.EventList1[0].Level, - amount: 1, - }) - } - newBattleConfig.monsters.push(newWave) - } - } - if ((moc_config.floor_side === "Lower" || moc_config.floor_side === "Lower -> Upper") && challengeSelected.EventList2.length > 0) { - newBattleConfig.stage_id = challengeSelected.EventList2[0].ID - for (const wave of challengeSelected.EventList2[0].MonsterList) { - const newWave: MonsterStore[] = [] - for (const value of Object.values(wave)) { - newWave.push({ - monster_id: value, - level: challengeSelected.EventList2[0].Level, - amount: 1, - }) - } - newBattleConfig.monsters.push(newWave) - } - } - if (moc_config.floor_side === "Lower -> Upper" && challengeSelected.EventList1.length > 0) { - for (const wave of challengeSelected.EventList1[0].MonsterList) { - const newWave: MonsterStore[] = [] - for (const value of Object.values(wave)) { - newWave.push({ - monster_id: value, - level: challengeSelected.EventList1[0].Level, - amount: 1, - }) - } - newBattleConfig.monsters.push(newWave) - } - } else if (moc_config.floor_side === "Upper -> Lower" && challengeSelected.EventList2.length > 0) { - for (const wave of challengeSelected.EventList2[0].MonsterList) { - const newWave: MonsterStore[] = [] - for (const value of Object.values(wave)) { - newWave.push({ - monster_id: value, - level: challengeSelected.EventList2[0].Level, + level: targetEventList[0].Level, amount: 1, }) } newBattleConfig.monsters.push(newWave) } } + setMocConfig(newBattleConfig) // eslint-disable-next-line react-hooks/exhaustive-deps }, [ + challengeSelected, + eventSelected, moc_config.event_id, moc_config.challenge_id, moc_config.floor_side, @@ -168,10 +169,9 @@ export default function MocBar() { onChange={(e) => setMocConfig({ ...moc_config, floor_side: e.target.value })} > - - - - + {floorSideList.map((side) => ( + + ))}
@@ -232,182 +232,108 @@ export default function MocBar() { {/* Enemy Waves */} {(moc_config?.challenge_id ?? 0) !== 0 && ( -
- {/* First Half */} -
-

{transI18n("firstHalfEnemies")}

+
+ {floorSideList.map((side, i) => { + const eventList = side.id === "firstNode" + ? challengeSelected?.EventList1 + : side.id === "secondNode" + ? challengeSelected?.EventList2 + : side.id === "thirdNode" + ? eventSelected?.Tierce?.EventList + : []; - {challengeSelected && challengeSelected?.EventList1?.length > 0 && challengeSelected?.EventList1?.[0]?.MonsterList?.map((wave, waveIndex) => ( -
-

{transI18n("wave")} {waveIndex + 1}

-
- {Object.values(wave).map((waveValue, enemyIndex) => { - const monsterStats = calcMonsterStats( - mapMonster?.[waveValue.toString()], - challengeSelected?.EventList1?.[0]?.EliteGroup, - challengeSelected?.EventList1?.[0]?.HardLevelGroup, - challengeSelected?.EventList1?.[0]?.Level, - hardLevelConfig, - eliteConfig - ); - return ( -
-
- Lv. {challengeSelected?.EventList1[0].Level} -
+ if (!eventList || eventList.length === 0) return null; + const targetEvent = eventList[0]; -
- {mapMonster?.[waveValue.toString()]?.Image?.IconPath && ( -
- Enemy Icon -
- )} -
+ return ( +
+

{side.wave}

-
-
-
- HP - {monsterStats.hp.toLocaleString(undefined, { maximumFractionDigits: 0 })} + {targetEvent?.MonsterList?.map((wave, waveIndex) => ( +
+

{transI18n("wave")} {waveIndex + 1}

+
+ {Object.values(wave).map((waveValue, enemyIndex) => { + const monsterStats = calcMonsterStats( + mapMonster?.[waveValue.toString()], + targetEvent?.EliteGroup, + targetEvent?.HardLevelGroup, + targetEvent?.Level, + hardLevelConfig, + eliteConfig + ); + return ( +
+
+ Lv. {targetEvent.Level}
-
- Speed - {monsterStats.spd.toLocaleString(undefined, { maximumFractionDigits: 0 })} +
+ {mapMonster?.[waveValue.toString()]?.Image?.IconPath && ( +
+ Enemy Icon +
+ )}
-
- Toughness - {monsterStats.stance.toLocaleString(undefined, { maximumFractionDigits: 0 })} +
+
+
+ HP + {monsterStats.hp.toLocaleString(undefined, { maximumFractionDigits: 0 })} +
+ +
+ Speed + {monsterStats.spd.toLocaleString(undefined, { maximumFractionDigits: 0 })} +
+ +
+ Toughness + {monsterStats.stance.toLocaleString(undefined, { maximumFractionDigits: 0 })} +
+
+ +
+ + Weakness + +
+ {mapMonster?.[waveValue.toString()]?.StanceWeakList?.map((icon, iconIndex) => ( + {icon} + ))} +
+
- -
- - Weakness - -
- {mapMonster?.[waveValue.toString()]?.StanceWeakList?.map((icon, iconIndex) => ( - {icon} - ))} -
-
-
-
- ) - })} -
+ ) + })} +
+
+ ))}
- ))} -
- - {/* Second Half */} -
-

{transI18n("secondHalfEnemies")}

- - {challengeSelected && challengeSelected?.EventList2?.length > 0 && challengeSelected?.EventList2?.[0]?.MonsterList?.map((wave, waveIndex) => ( -
-

{transI18n("wave")} {waveIndex + 1}

-
- {Object.values(wave).map((waveValue, enemyIndex) => { - const monsterStats = calcMonsterStats( - mapMonster?.[waveValue.toString()], - challengeSelected?.EventList2?.[0]?.EliteGroup, - challengeSelected?.EventList2?.[0]?.HardLevelGroup, - challengeSelected?.EventList2?.[0]?.Level, - hardLevelConfig, - eliteConfig - ); - return ( -
-
- Lv. {challengeSelected?.EventList2[0].Level} -
- -
- {mapMonster?.[waveValue.toString()]?.Image?.IconPath && ( -
- Enemy Icon -
- )} -
- -
-
-
- HP - {monsterStats.hp.toLocaleString(undefined, { maximumFractionDigits: 0 })} -
- -
- Speed - {monsterStats.spd.toLocaleString(undefined, { maximumFractionDigits: 0 })} -
- -
- Toughness - {monsterStats.stance.toLocaleString(undefined, { maximumFractionDigits: 0 })} -
-
- -
- - Weakness - -
- {mapMonster?.[waveValue.toString()]?.StanceWeakList?.map((icon, iconIndex) => ( - {icon} - ))} -
-
-
-
- ) - })} -
-
- ))} -
+ ) + })}
)} diff --git a/src/components/monsterBar/pf.tsx b/src/components/monsterBar/pf.tsx index 63317a3..d0bd1ef 100644 --- a/src/components/monsterBar/pf.tsx +++ b/src/components/monsterBar/pf.tsx @@ -5,7 +5,7 @@ import { calcMonsterStats, getLocaleName, replaceByParam } from "@/helper"; import useLocaleStore from "@/stores/localeStore"; import useUserDataStore from "@/stores/userDataStore"; import Image from "next/image"; -import { MonsterStore } from "@/types"; +import { MonsterStore, PFEvent } from "@/types"; import { useTranslations } from "next-intl"; import useDetailDataStore from "@/stores/detailDataStore"; @@ -26,6 +26,33 @@ export default function PfBar() { return mapPF[pf_config.event_id.toString()] }, [pf_config, mapPF]) + const floorSideList = useMemo(() => { + if (!eventSelected) return []; + + const floorList = [ + { + id: "firstNode", + name: transI18n("firstNode"), + wave: transI18n("firstNodeEnemies") + }, + { + id: "secondNode", + name: transI18n("secondNode"), + wave: transI18n("secondNodeEnemies") + }, + + ] + + if (eventSelected?.Tierce && eventSelected.Tierce.PreChallenge === pf_config.challenge_id) { + floorList.push({ + id: "thirdNode", + name: transI18n("thirdNode"), + wave: transI18n("thirdNodeEnemies") + }) + } + return floorList + }, [pf_config.challenge_id, eventSelected, transI18n]) + useEffect(() => { if (!challengeSelected || pf_config.event_id === 0 || pf_config.challenge_id === 0) { @@ -50,63 +77,36 @@ export default function PfBar() { } newBattleConfig.monsters = [] newBattleConfig.stage_id = 0 - if ((pf_config.floor_side === "Upper" || pf_config.floor_side === "Upper -> Lower") && challengeSelected.EventList1.length > 0) { - newBattleConfig.stage_id = challengeSelected.EventList1[0].ID - for (const wave of challengeSelected.EventList1[0].MonsterList) { + + let targetEventList: PFEvent[] = [] + if (pf_config.floor_side === "firstNode" && challengeSelected.EventList1.length > 0) { + targetEventList = challengeSelected.EventList1 + } else if (pf_config.floor_side === "secondNode" && challengeSelected.EventList2.length > 0) { + targetEventList = challengeSelected.EventList2 + } else if (pf_config.floor_side === "thirdNode" && eventSelected?.Tierce && eventSelected.Tierce.EventList.length > 0) { + targetEventList = eventSelected.Tierce.EventList + } + + if (targetEventList.length > 0) { + newBattleConfig.stage_id = targetEventList[0].ID + for (const wave of targetEventList[0].MonsterList) { const newWave: MonsterStore[] = [] for (const value of Object.values(wave)) { newWave.push({ - monster_id: value, - level: challengeSelected.EventList1[0].Level, - amount: 1, - }) - } - newBattleConfig.monsters.push(newWave) - } - } - if ((pf_config.floor_side === "Lower" || pf_config.floor_side === "Lower -> Upper") && challengeSelected.EventList2.length > 0) { - newBattleConfig.stage_id = challengeSelected.EventList2[0].ID - for (const wave of challengeSelected.EventList2[0].MonsterList) { - const newWave: MonsterStore[] = [] - for (const value of Object.values(wave)) { - newWave.push({ - monster_id: value, - level: challengeSelected.EventList2[0].Level, - amount: 1, - }) - } - newBattleConfig.monsters.push(newWave) - } - } - if (pf_config.floor_side === "Lower -> Upper" && challengeSelected.EventList1.length > 0) { - for (const wave of challengeSelected.EventList1[0].MonsterList) { - const newWave: MonsterStore[] = [] - for (const value of Object.values(wave)) { - newWave.push({ - monster_id: value, - level: challengeSelected.EventList1[0].Level, - amount: 1, - }) - } - newBattleConfig.monsters.push(newWave) - } - } else if (pf_config.floor_side === "Upper -> Lower" && challengeSelected.EventList2.length > 0) { - for (const wave of challengeSelected.EventList2[0].MonsterList) { - const newWave: MonsterStore[] = [] - for (const value of Object.values(wave)) { - newWave.push({ - monster_id: value, - level: challengeSelected.EventList2[0].Level, + monster_id: value as number, + level: targetEventList[0].Level, amount: 1, }) } newBattleConfig.monsters.push(newWave) } } + setPfConfig(newBattleConfig) // eslint-disable-next-line react-hooks/exhaustive-deps }, [ challengeSelected, + eventSelected, pf_config.event_id, pf_config.challenge_id, pf_config.floor_side, @@ -167,10 +167,9 @@ export default function PfBar() { onChange={(e) => setPfConfig({ ...pf_config, floor_side: e.target.value })} > - - - - + {floorSideList.map((side) => ( + + ))}
@@ -232,182 +231,108 @@ export default function PfBar() { {/* Enemy Waves */} {(pf_config?.challenge_id ?? 0) !== 0 && ( -
- {/* First Half */} -
-

{transI18n("firstHalfEnemies")}

- - {challengeSelected && Object.values(challengeSelected.EventList1?.[0]?.Infinite || []).map((waveValue, waveIndex) => ( -
-

{transI18n("wave")} {waveIndex + 1}

-
- {Array.from(new Set(waveValue.MonsterList)).map((monsterId, enemyIndex) => { - const monsterStats = calcMonsterStats( - mapMonster?.[monsterId.toString()], - waveValue.EliteGroup, - challengeSelected?.EventList1?.[0]?.HardLevelGroup, - challengeSelected?.EventList1?.[0]?.Level, - hardLevelConfig, - eliteConfig - ); - return ( -
-
- Lv. {challengeSelected?.EventList1[0].Level} -
+
+ {floorSideList.map((side, i) => { + const eventList = side.id === "firstNode" + ? challengeSelected?.EventList1 + : side.id === "secondNode" + ? challengeSelected?.EventList2 + : side.id === "thirdNode" + ? eventSelected?.Tierce?.EventList + : []; -
- {mapMonster?.[monsterId.toString()]?.Image?.IconPath && ( -
- Enemy Icon -
- )} -
+ if (!eventList || eventList.length === 0) return null; + const targetEvent = eventList[0]; -
-
-
- HP - {monsterStats.hp.toLocaleString(undefined, { maximumFractionDigits: 0 })} + return ( +
+

{side.wave}

+ + {targetEvent && Object.values(targetEvent.Infinite || []).map((waveValue, waveIndex) => ( +
+

{transI18n("wave")} {waveIndex + 1}

+
+ {Array.from(new Set(waveValue.MonsterList)).map((monsterId, enemyIndex) => { + const monsterStats = calcMonsterStats( + mapMonster?.[monsterId.toString()], + waveValue.EliteGroup, + targetEvent?.HardLevelGroup, + targetEvent?.Level, + hardLevelConfig, + eliteConfig + ); + return ( +
+
+ Lv. {targetEvent.Level}
-
- Speed - {monsterStats.spd.toLocaleString(undefined, { maximumFractionDigits: 0 })} +
+ {mapMonster?.[monsterId.toString()]?.Image?.IconPath && ( +
+ Enemy Icon +
+ )}
-
- Toughness - {monsterStats.stance.toLocaleString(undefined, { maximumFractionDigits: 0 })} +
+
+
+ HP + {monsterStats.hp.toLocaleString(undefined, { maximumFractionDigits: 0 })} +
+ +
+ Speed + {monsterStats.spd.toLocaleString(undefined, { maximumFractionDigits: 0 })} +
+ +
+ Toughness + {monsterStats.stance.toLocaleString(undefined, { maximumFractionDigits: 0 })} +
+
+ +
+ + Weakness + +
+ {mapMonster?.[monsterId.toString()]?.StanceWeakList?.map((icon, iconIndex) => ( + {icon} + ))} +
+
- -
- - Weakness - -
- {mapMonster?.[monsterId.toString()]?.StanceWeakList?.map((icon, iconIndex) => ( - {icon} - ))} -
-
-
-
- ) - })} -
+ ) + })} +
+
+ ))}
- ))} -
- - {/* Second Half */} -
-

{transI18n("secondHalfEnemies")}

- - {challengeSelected && Object.values(challengeSelected?.EventList2[0]?.Infinite || []).map((waveValue, waveIndex) => ( -
-

{transI18n("wave")} {waveIndex + 1}

-
- {Array.from(new Set(waveValue.MonsterList)).map((monsterId, enemyIndex) => { - const monsterStats = calcMonsterStats( - mapMonster?.[monsterId.toString()], - waveValue.EliteGroup, - challengeSelected?.EventList2?.[0]?.HardLevelGroup, - challengeSelected?.EventList2?.[0]?.Level, - hardLevelConfig, - eliteConfig - ); - return ( -
-
- Lv. {challengeSelected?.EventList2[0].Level} -
- -
- {mapMonster?.[monsterId.toString()]?.Image?.IconPath && ( -
- Enemy Icon -
- )} -
- -
-
-
- HP - {monsterStats.hp.toLocaleString(undefined, { maximumFractionDigits: 0 })} -
- -
- Speed - {monsterStats.spd.toLocaleString(undefined, { maximumFractionDigits: 0 })} -
- -
- Toughness - {monsterStats.stance.toLocaleString(undefined, { maximumFractionDigits: 0 })} -
-
- -
- - Weakness - -
- {mapMonster?.[monsterId.toString()]?.StanceWeakList?.map((icon, iconIndex) => ( - {icon} - ))} -
-
-
-
- ) - })} -
-
- ))} -
+ ) + })}
)} diff --git a/src/components/quickView/index.tsx b/src/components/quickView/index.tsx index fdabb58..186f88c 100644 --- a/src/components/quickView/index.tsx +++ b/src/components/quickView/index.tsx @@ -278,33 +278,33 @@ export default function QuickView() { if (avatarProfile?.lightcone && mapLightCone[avatarProfile?.lightcone?.item_id]) { const lightconePromotion = calcPromotion(avatarProfile?.lightcone?.level) statsData.HP.value += calcBaseStatRaw( - mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseHP, + mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseHP, mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseHPAdd, avatarProfile?.lightcone?.level ) statsData.HP.base += calcBaseStatRaw( - mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseHP, - mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseHPAdd, + mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseHP, + mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseHPAdd, avatarProfile?.lightcone?.level ) statsData.ATK.value += calcBaseStatRaw( - mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseAttack, - mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseAttackAdd, + mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseAttack, + mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseAttackAdd, avatarProfile?.lightcone?.level ) statsData.ATK.base += calcBaseStatRaw( - mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseAttack, - mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseAttackAdd, + mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseAttack, + mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseAttackAdd, avatarProfile?.lightcone?.level ) statsData.DEF.value += calcBaseStatRaw( - mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseDefence, - mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseDefenceAdd, + mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseDefence, + mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseDefenceAdd, avatarProfile?.lightcone?.level ) statsData.DEF.base += calcBaseStatRaw( - mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseDefence, - mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseDefenceAdd, + mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseDefence, + mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseDefenceAdd, avatarProfile?.lightcone?.level ) diff --git a/src/components/showcaseCard/index.tsx b/src/components/showcaseCard/index.tsx index eba07f8..bd0b3a4 100644 --- a/src/components/showcaseCard/index.tsx +++ b/src/components/showcaseCard/index.tsx @@ -95,20 +95,20 @@ export default function ShowCaseInfo() { if (!avatarSelected || !avatarProfile?.lightcone || !mapLightCone[avatarProfile?.lightcone?.item_id]) return const promotion = calcPromotion(avatarProfile?.lightcone?.level) const atkStat = calcBaseStat( - mapLightCone[avatarProfile?.lightcone?.item_id].Stats[promotion].BaseAttack, - mapLightCone[avatarProfile?.lightcone?.item_id].Stats[promotion].BaseAttackAdd, + mapLightCone[avatarProfile?.lightcone?.item_id]?.Stats?.[promotion]?.BaseAttack, + mapLightCone[avatarProfile?.lightcone?.item_id]?.Stats?.[promotion]?.BaseAttackAdd, 0, avatarProfile?.lightcone?.level ) const hpStat = calcBaseStat( - mapLightCone[avatarProfile?.lightcone?.item_id].Stats[promotion].BaseHP, - mapLightCone[avatarProfile?.lightcone?.item_id].Stats[promotion].BaseHPAdd, + mapLightCone[avatarProfile?.lightcone?.item_id]?.Stats?.[promotion]?.BaseHP, + mapLightCone[avatarProfile?.lightcone?.item_id]?.Stats?.[promotion]?.BaseHPAdd, 0, avatarProfile?.lightcone?.level ) const defStat = calcBaseStat( - mapLightCone[avatarProfile?.lightcone?.item_id].Stats[promotion].BaseDefence, - mapLightCone[avatarProfile?.lightcone?.item_id].Stats[promotion].BaseDefenceAdd, + mapLightCone[avatarProfile?.lightcone?.item_id]?.Stats?.[promotion]?.BaseDefence, + mapLightCone[avatarProfile?.lightcone?.item_id]?.Stats?.[promotion]?.BaseDefenceAdd, 0, avatarProfile?.lightcone?.level ) diff --git a/src/helper/calcData.ts b/src/helper/calcData.ts index 020e8bc..4201b81 100644 --- a/src/helper/calcData.ts +++ b/src/helper/calcData.ts @@ -24,7 +24,10 @@ export function calcPromotion(level: number) { } -export function calcRarity(rarity: string) { +export function calcRarity(rarity?: string) { + if (!rarity) { + return 1 + } if (rarity.includes("5")) { return 5 } @@ -40,11 +43,12 @@ export function calcRarity(rarity: string) { export function calcMainAffixBonus(affix?: MainAffixData, level?: number) { if (!affix || typeof level !== "number") return "0" const value = affix.BaseValue + affix.LevelAdd * level; + const statMeta = mappingStats[affix.Property] - if (mappingStats?.[affix.Property].unit === "%") { + if (statMeta?.unit === "%") { return (value * 100).toFixed(1); } - if (mappingStats?.[affix.Property].name === "SPD") { + if (statMeta?.name === "SPD") { return value.toFixed(1); } @@ -53,10 +57,11 @@ export function calcMainAffixBonus(affix?: MainAffixData, level?: number) { export const calcAffixBonus = (affix?: SubAffixData, stepCount?: number, rollCount?: number) => { if (!affix || typeof stepCount !== "number" || typeof rollCount !== "number") return "0" - if (mappingStats?.[affix.Property].unit === "%") { + const statMeta = mappingStats[affix.Property] + if (statMeta?.unit === "%") { return ((affix.BaseValue * rollCount + affix.StepValue * stepCount) * 100).toFixed(1); } - if (mappingStats?.[affix.Property].name === "SPD") { + if (statMeta?.name === "SPD") { return (affix.BaseValue * rollCount + affix.StepValue * stepCount).toFixed(1); } return (affix.BaseValue * rollCount + affix.StepValue * stepCount).toFixed(0); @@ -107,6 +112,16 @@ export const calcMonsterStats = ( hardLevelConfig: Record>, eliteConfig: Record ) => { + if (!monster?.Base || !monster?.Modify) { + return { + atk: 0, + def: 0, + hp: 0, + spd: 0, + stance: 0, + } + } + let hardLevelRatio = { AttackRatio: 1, DefenceRatio:1, @@ -135,4 +150,4 @@ export const calcMonsterStats = ( spd: monster.Base.SpeedBase * monster.Modify.SpeedModifyRatio * hardLevelRatio.SpeedRatio * eliteRatio.SpeedRatio, stance: (monster.Base.StanceBase * monster.Modify.StanceModifyRatio * hardLevelRatio.StanceRatio * eliteRatio.StanceRatio) / 3, } -} \ No newline at end of file +} diff --git a/src/helper/converterToAvatarStore.ts b/src/helper/converterToAvatarStore.ts index dfe5fe3..7641a23 100644 --- a/src/helper/converterToAvatarStore.ts +++ b/src/helper/converterToAvatarStore.ts @@ -15,7 +15,7 @@ export function converterToAvatarStore(data: Record): { [k avatar_id: Number(key), data: { rank: 0, - skills: Object.values(value.SkillTrees).reduce((acc, dataPointEntry) => { + skills: Object.values(value.SkillTrees ?? {}).reduce((acc, dataPointEntry) => { const firstEntry = Object.values(dataPointEntry)[0]; if (firstEntry) { acc[firstEntry.PointID] = firstEntry.MaxLevel; @@ -42,7 +42,8 @@ export function converterToAvatarStore(data: Record): { [k } export function converterOneEnkaDataToAvatarStore(data: AvatarEnkaDetail, count: number): AvatarProfileStore | null { - if (!data.equipment && (!data.relicList || data.relicList.length === 0)) return null + const relicList = data.relicList ?? [] + if (!data.equipment && relicList.length === 0) return null const profile: AvatarProfileStore = { profile_name: `Enka Profile ${count}`, lightcone: (data.equipment && data.equipment.tid) ? { @@ -51,12 +52,12 @@ export function converterOneEnkaDataToAvatarStore(data: AvatarEnkaDetail, count: rank: data.equipment?.rank ?? 0, promotion: data.equipment?.promotion ?? 0, } : null, - relics: Object.fromEntries(data.relicList.map((relic) => [relic.tid.toString()[relic.tid.toString().length - 1], { + relics: Object.fromEntries(relicList.map((relic) => [relic.tid.toString()[relic.tid.toString().length - 1], { level: relic.level ?? 0, relic_id: relic.tid, relic_set_id: parseInt(relic.tid.toString().slice(1, -1), 10), main_affix_id: relic.mainAffixId, - sub_affixes: relic.subAffixList.map((subAffix) => ({ + sub_affixes: (relic.subAffixList ?? []).map((subAffix) => ({ sub_affix_id: subAffix.affixId, count: subAffix.cnt, step: subAffix.step ?? 0 @@ -68,8 +69,8 @@ export function converterOneEnkaDataToAvatarStore(data: AvatarEnkaDetail, count: export function converterOneFreeSRDataToAvatarStore(data: FreeSRJson, count: number , avatar_id: number): AvatarProfileStore | null { - const lightcone = data.lightcones.find((lightcone) => lightcone.equip_avatar === avatar_id) - const relics = data.relics.filter((relic) => relic.equip_avatar === avatar_id) + const lightcone = (data.lightcones ?? []).find((lightcone) => lightcone.equip_avatar === avatar_id) + const relics = (data.relics ?? []).filter((relic) => relic.equip_avatar === avatar_id) if (!lightcone && (!relics || relics.length === 0)) return null const relicsMap = {} as Record @@ -79,7 +80,7 @@ export function converterOneFreeSRDataToAvatarStore(data: FreeSRJson, count: num relic_id: relic.relic_id, relic_set_id: relic.relic_set_id, main_affix_id: relic.main_affix_id, - sub_affixes: relic.sub_affixes.map((subAffix) => ({ + sub_affixes: (relic.sub_affixes ?? []).map((subAffix) => ({ sub_affix_id: subAffix.sub_affix_id, count: subAffix.count, step: subAffix.step ?? 0 diff --git a/src/helper/converterToFreeSRJson.ts b/src/helper/converterToFreeSRJson.ts index fcf1896..958ced3 100644 --- a/src/helper/converterToFreeSRJson.ts +++ b/src/helper/converterToFreeSRJson.ts @@ -84,7 +84,9 @@ export function converterToFreeSRJson( let internalUidLightcone = 0 let internalUidRelic = 0 - Object.entries(avatars).forEach(([avatarId, avatar]) => { + Object.entries(avatars ?? {}).forEach(([avatarId, avatar]) => { + if (!avatar) return + const skillsByAnchorType: Record = {} for (const [skillId, level] of Object.entries(avatar?.data?.skills || {})) { if (skillConfig?.[skillId]) { @@ -95,17 +97,20 @@ export function converterToFreeSRJson( owner_uid: Number(avatar.owner_uid || 0), avatar_id: Number(avatar.avatar_id || 0), data: { - rank: Number(avatar.data.rank || 0), - skills: avatar.data.skills, + rank: Number(avatar.data?.rank || 0), + skills: avatar.data?.skills ?? {}, skills_by_anchor_type: Object.keys(skillsByAnchorType).length > 0 ? skillsByAnchorType : undefined, }, level: Number(avatar.level || 0), promotion: Number(avatar.promotion || 0), - techniques: avatar.techniques, + techniques: avatar.techniques ?? [], sp_value: Number(avatar.sp_value || 0), sp_max: Number(avatar.sp_max || 0), + enhanced_id: avatar.enhanced ? Number(avatar.enhanced || 0) : undefined, } - const currentProfile = avatar.profileList[avatar.profileSelect] + const currentProfile = avatar.profileList?.[avatar.profileSelect] ?? avatar.profileList?.[0] + if (!currentProfile) return + if (currentProfile.lightcone && currentProfile.lightcone.item_id !== 0) { const newLightcone: LightconeJson = { level: Number(currentProfile.lightcone.level || 0), @@ -128,7 +133,7 @@ export function converterToFreeSRJson( relic_id: Number(relic.relic_id || 0), relic_set_id: Number(relic.relic_set_id || 0), main_affix_id: Number(relic.main_affix_id || 0), - sub_affixes: relic.sub_affixes, + sub_affixes: relic.sub_affixes ?? [], internal_uid: internalUidRelic, equip_avatar: Number(avatar.avatar_id || 0), } @@ -146,4 +151,4 @@ export function converterToFreeSRJson( avatars: avatarsJson, battle_config: battleJson, } -} \ No newline at end of file +} diff --git a/src/helper/getName.ts b/src/helper/getName.ts index 0560298..273f461 100644 --- a/src/helper/getName.ts +++ b/src/helper/getName.ts @@ -43,8 +43,6 @@ export function getLocaleName(locale: string, data: Record | und return "" } - - const langKey = listCurrentLanguageApi[locale as keyof typeof listCurrentLanguageApi].toLowerCase(); let text = data[langKey] ?? ""; diff --git a/src/helper/getSkillTree.ts b/src/helper/getSkillTree.ts index 4fd5e8e..e886e5e 100644 --- a/src/helper/getSkillTree.ts +++ b/src/helper/getSkillTree.ts @@ -12,7 +12,7 @@ export function getSkillTree(avatarSelected: AvatarDetail | null, enhanced: stri }, {} as Record) } - return Object.values(avatarSelected?.SkillTrees).reduce((acc, dataPointEntry) => { + return Object.values(avatarSelected?.SkillTrees ?? {}).reduce((acc, dataPointEntry) => { const firstEntry = Object.values(dataPointEntry)[0]; if (firstEntry) { acc[firstEntry.PointID] = firstEntry.MaxLevel; diff --git a/src/helper/json.ts b/src/helper/json.ts index c484958..07f78ea 100644 --- a/src/helper/json.ts +++ b/src/helper/json.ts @@ -1,15 +1,23 @@ // eslint-disable-next-line @typescript-eslint/no-explicit-any -export function downloadJson(fileName: string, data: any) { - const json = JSON.stringify(data, null, 2) - const blob = new Blob([json], { type: 'application/json' }) - const url = URL.createObjectURL(blob) +export function downloadJson(fileName: string, data: any): boolean { + if (typeof document === "undefined") return false - const link = document.createElement('a') - link.href = url - link.download = `${fileName}.json` - document.body.appendChild(link) - link.click() - document.body.removeChild(link) + try { + const json = JSON.stringify(data, null, 2) + const blob = new Blob([json], { type: 'application/json' }) + const url = URL.createObjectURL(blob) - URL.revokeObjectURL(url) + const link = document.createElement('a') + link.href = url + link.download = `${fileName}.json` + document.body.appendChild(link) + link.click() + document.body.removeChild(link) + + URL.revokeObjectURL(url) + return true + } catch (error) { + console.error("Failed to download JSON:", error) + return false + } } diff --git a/src/helper/random.ts b/src/helper/random.ts index 206575a..b7a5156 100644 --- a/src/helper/random.ts +++ b/src/helper/random.ts @@ -1,4 +1,11 @@ export function randomPartition(sum: number, parts: number): number[] { + if (!Number.isFinite(sum) || !Number.isInteger(parts) || parts <= 0) { + return []; + } + if (sum < parts) { + return Array.from({ length: parts }, () => 0); + } + const raw = Array.from({ length: parts }, () => Math.random()); const total = raw.reduce((a, b) => a + b, 0); const result = raw.map(r => Math.floor((r / total) * (sum - parts)) + 1); @@ -24,4 +31,4 @@ export function randomStep(x: number): number { total += Math.floor(Math.random() * 3); } return total; -} \ No newline at end of file +} diff --git a/src/helper/replaceByParam.ts b/src/helper/replaceByParam.ts index f14fd53..2f8dd38 100644 --- a/src/helper/replaceByParam.ts +++ b/src/helper/replaceByParam.ts @@ -13,7 +13,8 @@ const formatValue = (value: number, format: string, floatDigits?: string, hasPer return String(value); }; -export function replaceByParam(desc: string, params: number[]): string { +export function replaceByParam(desc?: string, params: number[] = []): string { + if (!desc) return ""; const PARAM_REGEX = /#(\d+)\[(f(\d+)|i)\](%)?/g; @@ -35,4 +36,4 @@ export function replaceByParam(desc: string, params: number[]): string { result = result.replace(PARAM_REGEX, processor); return result.split("\\n").join("
"); -} \ No newline at end of file +} diff --git a/src/stores/connectStore.ts b/src/stores/connectStore.ts index 9f4928c..a7d9c77 100644 --- a/src/stores/connectStore.ts +++ b/src/stores/connectStore.ts @@ -1,5 +1,7 @@ import { create } from 'zustand' -import { createJSONStorage, persist } from 'zustand/middleware'; +import { persist } from 'zustand/middleware'; +import { connectPersistedSchema } from '@/zod'; +import { createValidatedJSONStorage } from './persistStorage'; interface ConnectState { @@ -15,8 +17,10 @@ interface ConnectState { setPassword: (newPassword: string) => void; } +type ConnectPersistedState = Pick; + const useConnectStore = create()( - persist( + persist( (set) => ({ connectionType: "FireflyGo", privateType: "Local", @@ -31,9 +35,16 @@ const useConnectStore = create()( }), { name: 'connect-storage', - storage: createJSONStorage(() => localStorage), + storage: createValidatedJSONStorage(() => localStorage, connectPersistedSchema), + partialize: (state) => ({ + connectionType: state.connectionType, + privateType: state.privateType, + serverUrl: state.serverUrl, + username: state.username, + password: state.password, + }), } ) ); -export default useConnectStore; \ No newline at end of file +export default useConnectStore; diff --git a/src/stores/enkaStore.ts b/src/stores/enkaStore.ts index 28b3211..8a6c35a 100644 --- a/src/stores/enkaStore.ts +++ b/src/stores/enkaStore.ts @@ -6,7 +6,7 @@ interface EnkaState { enkaData: EnkaResponse | null; uidInput: string; setSelectedCharacters: (newListAvatar: CharacterInfoCardType[]) => void; - setEnkaData: (newEnkaData: EnkaResponse) => void; + setEnkaData: (newEnkaData: EnkaResponse | null) => void; setUidInput: (newUidInput: string) => void; } @@ -16,7 +16,7 @@ const useEnkaStore = create((set) => ({ uidInput: "", setUidInput: (newUidInput: string) => set({ uidInput: newUidInput }), setSelectedCharacters: (newListAvatar: CharacterInfoCardType[]) => set({ selectedCharacters: newListAvatar }), - setEnkaData: (newEnkaData: EnkaResponse) => set({ enkaData: newEnkaData }), + setEnkaData: (newEnkaData: EnkaResponse | null) => set({ enkaData: newEnkaData }), })); -export default useEnkaStore; \ No newline at end of file +export default useEnkaStore; diff --git a/src/stores/localeStore.ts b/src/stores/localeStore.ts index 419ffbc..38da530 100644 --- a/src/stores/localeStore.ts +++ b/src/stores/localeStore.ts @@ -1,6 +1,8 @@ import { ChangelogItemType } from '@/types'; import { create } from 'zustand' -import { createJSONStorage, persist } from 'zustand/middleware'; +import { persist } from 'zustand/middleware'; +import { localePersistedSchema } from '@/zod'; +import { createValidatedJSONStorage } from './persistStorage'; interface LocaleState { @@ -14,8 +16,10 @@ interface LocaleState { setLocale: (newLocale: string) => void; } +type LocalePersistedState = Pick; + const useLocaleStore = create()( - persist( + persist( (set) => ({ locale: "en", theme: "night", @@ -28,9 +32,15 @@ const useLocaleStore = create()( }), { name: 'locale-storage', - storage: createJSONStorage(() => localStorage), + storage: createValidatedJSONStorage(() => localStorage, localePersistedSchema), + partialize: (state) => ({ + locale: state.locale, + theme: state.theme, + currentVersion: state.currentVersion, + changelog: state.changelog, + }), } ) ); -export default useLocaleStore; \ No newline at end of file +export default useLocaleStore; diff --git a/src/stores/persistStorage.ts b/src/stores/persistStorage.ts new file mode 100644 index 0000000..46722a0 --- /dev/null +++ b/src/stores/persistStorage.ts @@ -0,0 +1,79 @@ +import type { PersistStorage, StateStorage, StorageValue } from "zustand/middleware"; +import type { ZodType } from "zod"; + +export function createValidatedJSONStorage( + getStorage: () => StateStorage, + stateSchema: ZodType +): PersistStorage | undefined { + let storage: StateStorage; + + try { + storage = getStorage(); + } catch { + return undefined; + } + + const removeInvalidItem = (name: string, reason: string) => { + console.warn(`Invalid persisted store "${name}" was cleared: ${reason}`); + storage.removeItem(name); + }; + + return { + getItem: (name) => { + const raw = storage.getItem(name); + + if (raw === null) { + return null; + } + + if (raw instanceof Promise) { + return raw.then((value) => parseStorageValue(name, value, stateSchema, removeInvalidItem)); + } + + return parseStorageValue(name, raw, stateSchema, removeInvalidItem); + }, + setItem: (name, value) => { + storage.setItem(name, JSON.stringify(value)); + }, + removeItem: (name) => { + storage.removeItem(name); + }, + }; +} + +function parseStorageValue( + name: string, + raw: string | null, + stateSchema: ZodType, + removeInvalidItem: (name: string, reason: string) => void +): StorageValue | null { + if (raw === null) { + return null; + } + + let parsed: unknown; + try { + parsed = JSON.parse(raw); + } catch { + removeInvalidItem(name, "malformed JSON"); + return null; + } + + if (!parsed || typeof parsed !== "object" || !("state" in parsed)) { + removeInvalidItem(name, "missing persisted state"); + return null; + } + + const storedValue = parsed as StorageValue; + const state = stateSchema.safeParse(storedValue.state); + + if (!state.success) { + removeInvalidItem(name, "state schema mismatch"); + return null; + } + + return { + state: state.data, + version: typeof storedValue.version === "number" ? storedValue.version : undefined, + }; +} diff --git a/src/stores/userDataStore.ts b/src/stores/userDataStore.ts index 134f236..63b0d35 100644 --- a/src/stores/userDataStore.ts +++ b/src/stores/userDataStore.ts @@ -1,6 +1,8 @@ import { ASConfigStore, AvatarStore, CEConfigStore, MOCConfigStore, PEAKConfigStore, PFConfigStore } from '@/types'; import { create } from 'zustand' -import { createJSONStorage, persist } from 'zustand/middleware'; +import { persist } from 'zustand/middleware'; +import { micsSchema } from '@/zod'; +import { createValidatedJSONStorage } from './persistStorage'; interface UserDataState { @@ -21,8 +23,19 @@ interface UserDataState { setCeConfig: (newCeConfig: CEConfigStore) => void; } +type UserDataPersistedState = Pick< + UserDataState, + | "avatars" + | "battle_type" + | "moc_config" + | "pf_config" + | "as_config" + | "peak_config" + | "ce_config" +>; + const useUserDataStore = create()( - persist( + persist( (set) => ({ avatars: {}, battle_type: "", @@ -84,9 +97,18 @@ const useUserDataStore = create()( }), { name: 'user-data-storage', - storage: createJSONStorage(() => localStorage), + storage: createValidatedJSONStorage(() => localStorage, micsSchema), + partialize: (state) => ({ + avatars: state.avatars, + battle_type: state.battle_type, + moc_config: state.moc_config, + pf_config: state.pf_config, + as_config: state.as_config, + peak_config: state.peak_config, + ce_config: state.ce_config, + }), } ) ); -export default useUserDataStore; \ No newline at end of file +export default useUserDataStore; diff --git a/src/types/asDetail.ts b/src/types/asDetail.ts index 5c21b07..989dc19 100644 --- a/src/types/asDetail.ts +++ b/src/types/asDetail.ts @@ -9,7 +9,9 @@ export interface ASGroupDetail { EndTime: string; BuffList1: ASBuff[]; BuffList2: ASBuff[]; + BuffList3: ASBuff[] | null; Level: ASLevel[]; + Tierce: ASTierceLevel | null; } export interface ASBuff { @@ -21,6 +23,16 @@ export interface ASBuff { ExtraList?: ExtraEffect[]; } +export interface ASTierceLevel { + ID: number; + PreChallenge: number; + Name: Record; + Target: ASTarget[]; + DamageType: string[]; + TurnLimit: number; + EventList: ASEvent[]; +} + export interface ASLevel { Floor: number; ID: number; @@ -35,6 +47,7 @@ export interface ASLevel { EventList2: ASEvent[]; Monster1: ASMonster; Monster2: ASMonster; + Monster3: ASMonster | null; } export interface ASTarget { diff --git a/src/types/enka.ts b/src/types/enka.ts index 47c15a6..4551bcc 100644 --- a/src/types/enka.ts +++ b/src/types/enka.ts @@ -31,7 +31,7 @@ interface FlatProp { interface RelicFlat { props: FlatProp[] - setName: string + setName: string | number setID: number } @@ -51,7 +51,7 @@ interface SkillTree { interface EquipmentFlat { props: FlatProp[] - name: string + name: string | number } interface Equipment { diff --git a/src/types/mocDetail.ts b/src/types/mocDetail.ts index f7b1863..12e0b76 100644 --- a/src/types/mocDetail.ts +++ b/src/types/mocDetail.ts @@ -7,6 +7,17 @@ export interface MOCGroupDetail { BeginTime: string; EndTime: string; Level: MoCLevel[]; + Tierce: MoCTierceLevel | null; +} + +export interface MoCTierceLevel { + ID: number; + PreChallenge: number; + Name: Record; + Target: MoCTarget[]; + DamageType: string[]; + TurnLimit: number; + EventList: MoCEvent[]; } export interface MoCLevel { diff --git a/src/types/pfDetail.ts b/src/types/pfDetail.ts index b18639d..3866c8b 100644 --- a/src/types/pfDetail.ts +++ b/src/types/pfDetail.ts @@ -6,7 +6,8 @@ export interface PFGroupDetail { EndTime: string; SubOption: MazeBuff[]; Option: MazeBuff[]; - Level: LevelData[]; + Level: PFLevel[]; + Tierce: PFTierceLevel | null; } export interface MazeBuff { @@ -17,7 +18,17 @@ export interface MazeBuff { Desc: Record; } -export interface LevelData { +export interface PFTierceLevel { + ID: number; + PreChallenge: number; + Name: Record; + Target: StoryTarget[]; + DamageType: string[]; + TurnLimit: number; + EventList: PFEvent[]; +} + +export interface PFLevel { Floor: number; ID: number; StageNum: number; @@ -26,8 +37,8 @@ export interface LevelData { DamageType1: string[]; DamageType2: string[]; MazeBuff: MazeBuff[]; - EventList1: StageConfig[]; - EventList2: StageConfig[]; + EventList1: PFEvent[]; + EventList2: PFEvent[]; TurnLimit: number; BattleTarget: BattleTarget[]; ClearScore: number; @@ -45,7 +56,7 @@ export interface BattleTarget { Name: Record; } -export interface StageConfig { +export interface PFEvent { ID: number; Name: Record; HardLevelGroup: number; diff --git a/src/types/srtools.ts b/src/types/srtools.ts index f829675..1db5ecb 100644 --- a/src/types/srtools.ts +++ b/src/types/srtools.ts @@ -37,6 +37,7 @@ export interface AvatarJson { techniques: number[]; sp_value: number; sp_max: number; + enhanced_id?: number; } export interface MonsterJson { monster_id: number; @@ -49,7 +50,6 @@ export interface DynamicKeyJson { value: number; } -//BattleBuff export interface BattleBuffJson { level: number; id: number; diff --git a/src/zod/card.zod.ts b/src/zod/card.zod.ts index 89557ca..5ed9478 100644 --- a/src/zod/card.zod.ts +++ b/src/zod/card.zod.ts @@ -1,5 +1,6 @@ // Generated by ts-to-zod import { z } from "zod"; +import { lightconeStoreSchema, relicStoreSchema } from "./mics.zod"; export const characterInfoCardTypeSchema = z.object({ key: z.number(), @@ -18,10 +19,6 @@ export const characterInfoCardTypeSchema = z.object({ })) }); -const lightconeStoreSchema = z.any(); - -const relicStoreSchema = z.any(); - export const avatarProfileCardTypeSchema = z.object({ key: z.number(), profile_name: z.string(), diff --git a/src/zod/enka.zod.ts b/src/zod/enka.zod.ts index d87879e..69f51f9 100644 --- a/src/zod/enka.zod.ts +++ b/src/zod/enka.zod.ts @@ -33,7 +33,7 @@ const flatPropSchema = z.object({ const relicFlatSchema = z.object({ props: z.array(flatPropSchema), - setName: z.string(), + setName: z.union([z.string(), z.number()]), setID: z.number() }); @@ -53,7 +53,7 @@ const skillTreeSchema = z.object({ const equipmentFlatSchema = z.object({ props: z.array(flatPropSchema), - name: z.string() + name: z.union([z.string(), z.number()]) }); const equipmentSchema = z.object({ diff --git a/src/zod/index.ts b/src/zod/index.ts index 99e5817..87e0fea 100644 --- a/src/zod/index.ts +++ b/src/zod/index.ts @@ -5,5 +5,6 @@ export * from "./enka.zod" export * from "./card.zod" export * from "./extraData.zod" export * from "./showcase.zod" +export * from "./persistedStore.zod" export * from "./srtools.zod" diff --git a/src/zod/mics.zod.ts b/src/zod/mics.zod.ts index caae13a..e3c9013 100644 --- a/src/zod/mics.zod.ts +++ b/src/zod/mics.zod.ts @@ -125,4 +125,22 @@ export const micsSchema = z.object({ as_config: asConfigStoreSchema, ce_config: ceConfigStoreSchema, peak_config: peakConfigStoreSchema +}).superRefine((data, ctx) => { + for (const [avatarId, avatar] of Object.entries(data.avatars)) { + if (avatar.profileList.length === 0) { + ctx.addIssue({ + code: "custom", + path: ["avatars", avatarId, "profileList"], + message: "profileList must contain at least one profile" + }); + } + + if (avatar.profileSelect < 0 || avatar.profileSelect >= avatar.profileList.length) { + ctx.addIssue({ + code: "custom", + path: ["avatars", avatarId, "profileSelect"], + message: "profileSelect must point to an existing profile" + }); + } + } }); diff --git a/src/zod/persistedStore.zod.ts b/src/zod/persistedStore.zod.ts new file mode 100644 index 0000000..07edac5 --- /dev/null +++ b/src/zod/persistedStore.zod.ts @@ -0,0 +1,24 @@ +import { z } from "zod"; +import type { ChangelogItemType } from "@/types"; + +export const changelogItemSchema: z.ZodType = z.object({ + version: z.string(), + date: z.string(), + type: z.string(), + items: z.array(z.string()), +}); + +export const localePersistedSchema = z.object({ + locale: z.string(), + theme: z.string(), + currentVersion: z.string(), + changelog: z.array(changelogItemSchema), +}); + +export const connectPersistedSchema = z.object({ + connectionType: z.string(), + privateType: z.string(), + serverUrl: z.string(), + username: z.string(), + password: z.string(), +}); diff --git a/src/zod/srtools.zod.ts b/src/zod/srtools.zod.ts index ee74856..a024dde 100644 --- a/src/zod/srtools.zod.ts +++ b/src/zod/srtools.zod.ts @@ -40,7 +40,8 @@ export const avatarJsonSchema = z.object({ promotion: z.number(), techniques: z.array(z.number()), sp_value: z.number(), - sp_max: z.number() + sp_max: z.number(), + enhanced_id: z.number().optional() }); export const monsterJsonSchema = z.object({