更新依赖,优化认证流程;添加聊天框动画效果,优化消息处理逻辑

This commit is contained in:
2026-03-24 10:56:25 +08:00
parent accf6ad254
commit 045391d036
9 changed files with 879 additions and 326 deletions
+331 -216
View File
@@ -31,6 +31,7 @@
"deck.gl": "^9.1.14", "deck.gl": "^9.1.14",
"echarts": "^6.0.0", "echarts": "^6.0.0",
"echarts-for-react": "^3.0.5", "echarts-for-react": "^3.0.5",
"framer-motion": "^12.38.0",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"next": "^16.1.6", "next": "^16.1.6",
"next-auth": "^4.24.5", "next-auth": "^4.24.5",
@@ -2582,9 +2583,9 @@
} }
}, },
"node_modules/@emnapi/runtime": { "node_modules/@emnapi/runtime": {
"version": "1.5.0", "version": "1.9.1",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz",
"integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", "integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==",
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"dependencies": { "dependencies": {
@@ -2855,9 +2856,9 @@
} }
}, },
"node_modules/@eslint/eslintrc/node_modules/ajv": { "node_modules/@eslint/eslintrc/node_modules/ajv": {
"version": "6.12.6", "version": "6.14.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -3006,9 +3007,9 @@
} }
}, },
"node_modules/@img/colour": { "node_modules/@img/colour": {
"version": "1.0.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz",
"integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==",
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"engines": { "engines": {
@@ -3016,9 +3017,9 @@
} }
}, },
"node_modules/@img/sharp-darwin-arm64": { "node_modules/@img/sharp-darwin-arm64": {
"version": "0.34.4", "version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.4.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz",
"integrity": "sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA==", "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -3034,13 +3035,13 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
}, },
"optionalDependencies": { "optionalDependencies": {
"@img/sharp-libvips-darwin-arm64": "1.2.3" "@img/sharp-libvips-darwin-arm64": "1.2.4"
} }
}, },
"node_modules/@img/sharp-darwin-x64": { "node_modules/@img/sharp-darwin-x64": {
"version": "0.34.4", "version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.4.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz",
"integrity": "sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg==", "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -3056,13 +3057,13 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
}, },
"optionalDependencies": { "optionalDependencies": {
"@img/sharp-libvips-darwin-x64": "1.2.3" "@img/sharp-libvips-darwin-x64": "1.2.4"
} }
}, },
"node_modules/@img/sharp-libvips-darwin-arm64": { "node_modules/@img/sharp-libvips-darwin-arm64": {
"version": "1.2.3", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz",
"integrity": "sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw==", "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -3076,9 +3077,9 @@
} }
}, },
"node_modules/@img/sharp-libvips-darwin-x64": { "node_modules/@img/sharp-libvips-darwin-x64": {
"version": "1.2.3", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz",
"integrity": "sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA==", "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -3092,9 +3093,9 @@
} }
}, },
"node_modules/@img/sharp-libvips-linux-arm": { "node_modules/@img/sharp-libvips-linux-arm": {
"version": "1.2.3", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz",
"integrity": "sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA==", "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -3108,9 +3109,9 @@
} }
}, },
"node_modules/@img/sharp-libvips-linux-arm64": { "node_modules/@img/sharp-libvips-linux-arm64": {
"version": "1.2.3", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz",
"integrity": "sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ==", "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -3124,9 +3125,9 @@
} }
}, },
"node_modules/@img/sharp-libvips-linux-ppc64": { "node_modules/@img/sharp-libvips-linux-ppc64": {
"version": "1.2.3", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz",
"integrity": "sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg==", "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@@ -3139,10 +3140,26 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
} }
}, },
"node_modules/@img/sharp-libvips-linux-riscv64": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz",
"integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==",
"cpu": [
"riscv64"
],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-s390x": { "node_modules/@img/sharp-libvips-linux-s390x": {
"version": "1.2.3", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz",
"integrity": "sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w==", "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@@ -3156,9 +3173,9 @@
} }
}, },
"node_modules/@img/sharp-libvips-linux-x64": { "node_modules/@img/sharp-libvips-linux-x64": {
"version": "1.2.3", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz",
"integrity": "sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg==", "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -3172,9 +3189,9 @@
} }
}, },
"node_modules/@img/sharp-libvips-linuxmusl-arm64": { "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
"version": "1.2.3", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz",
"integrity": "sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw==", "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -3188,9 +3205,9 @@
} }
}, },
"node_modules/@img/sharp-libvips-linuxmusl-x64": { "node_modules/@img/sharp-libvips-linuxmusl-x64": {
"version": "1.2.3", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz",
"integrity": "sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g==", "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -3204,9 +3221,9 @@
} }
}, },
"node_modules/@img/sharp-linux-arm": { "node_modules/@img/sharp-linux-arm": {
"version": "0.34.4", "version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.4.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz",
"integrity": "sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA==", "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -3222,13 +3239,13 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
}, },
"optionalDependencies": { "optionalDependencies": {
"@img/sharp-libvips-linux-arm": "1.2.3" "@img/sharp-libvips-linux-arm": "1.2.4"
} }
}, },
"node_modules/@img/sharp-linux-arm64": { "node_modules/@img/sharp-linux-arm64": {
"version": "0.34.4", "version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.4.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz",
"integrity": "sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ==", "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -3244,13 +3261,13 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
}, },
"optionalDependencies": { "optionalDependencies": {
"@img/sharp-libvips-linux-arm64": "1.2.3" "@img/sharp-libvips-linux-arm64": "1.2.4"
} }
}, },
"node_modules/@img/sharp-linux-ppc64": { "node_modules/@img/sharp-linux-ppc64": {
"version": "0.34.4", "version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.4.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz",
"integrity": "sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ==", "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@@ -3266,13 +3283,35 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
}, },
"optionalDependencies": { "optionalDependencies": {
"@img/sharp-libvips-linux-ppc64": "1.2.3" "@img/sharp-libvips-linux-ppc64": "1.2.4"
}
},
"node_modules/@img/sharp-linux-riscv64": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz",
"integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==",
"cpu": [
"riscv64"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-riscv64": "1.2.4"
} }
}, },
"node_modules/@img/sharp-linux-s390x": { "node_modules/@img/sharp-linux-s390x": {
"version": "0.34.4", "version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.4.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz",
"integrity": "sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw==", "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@@ -3288,13 +3327,13 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
}, },
"optionalDependencies": { "optionalDependencies": {
"@img/sharp-libvips-linux-s390x": "1.2.3" "@img/sharp-libvips-linux-s390x": "1.2.4"
} }
}, },
"node_modules/@img/sharp-linux-x64": { "node_modules/@img/sharp-linux-x64": {
"version": "0.34.4", "version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.4.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz",
"integrity": "sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A==", "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -3310,13 +3349,13 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
}, },
"optionalDependencies": { "optionalDependencies": {
"@img/sharp-libvips-linux-x64": "1.2.3" "@img/sharp-libvips-linux-x64": "1.2.4"
} }
}, },
"node_modules/@img/sharp-linuxmusl-arm64": { "node_modules/@img/sharp-linuxmusl-arm64": {
"version": "0.34.4", "version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.4.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz",
"integrity": "sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA==", "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -3332,13 +3371,13 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
}, },
"optionalDependencies": { "optionalDependencies": {
"@img/sharp-libvips-linuxmusl-arm64": "1.2.3" "@img/sharp-libvips-linuxmusl-arm64": "1.2.4"
} }
}, },
"node_modules/@img/sharp-linuxmusl-x64": { "node_modules/@img/sharp-linuxmusl-x64": {
"version": "0.34.4", "version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.4.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz",
"integrity": "sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg==", "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -3354,20 +3393,20 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
}, },
"optionalDependencies": { "optionalDependencies": {
"@img/sharp-libvips-linuxmusl-x64": "1.2.3" "@img/sharp-libvips-linuxmusl-x64": "1.2.4"
} }
}, },
"node_modules/@img/sharp-wasm32": { "node_modules/@img/sharp-wasm32": {
"version": "0.34.4", "version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.4.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz",
"integrity": "sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA==", "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==",
"cpu": [ "cpu": [
"wasm32" "wasm32"
], ],
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
"optional": true, "optional": true,
"dependencies": { "dependencies": {
"@emnapi/runtime": "^1.5.0" "@emnapi/runtime": "^1.7.0"
}, },
"engines": { "engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0" "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
@@ -3377,9 +3416,9 @@
} }
}, },
"node_modules/@img/sharp-win32-arm64": { "node_modules/@img/sharp-win32-arm64": {
"version": "0.34.4", "version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.4.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz",
"integrity": "sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA==", "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -3396,9 +3435,9 @@
} }
}, },
"node_modules/@img/sharp-win32-ia32": { "node_modules/@img/sharp-win32-ia32": {
"version": "0.34.4", "version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.4.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz",
"integrity": "sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw==", "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@@ -3415,9 +3454,9 @@
} }
}, },
"node_modules/@img/sharp-win32-x64": { "node_modules/@img/sharp-win32-x64": {
"version": "0.34.4", "version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.4.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz",
"integrity": "sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig==", "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -5381,9 +5420,9 @@
} }
}, },
"node_modules/@next/env": { "node_modules/@next/env": {
"version": "16.1.6", "version": "16.2.1",
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz", "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.1.tgz",
"integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==", "integrity": "sha512-n8P/HCkIWW+gVal2Z8XqXJ6aB3J0tuM29OcHpCsobWlChH/SITBs1DFBk/HajgrwDkqqBXPbuUuzgDvUekREPg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@next/eslint-plugin-next": { "node_modules/@next/eslint-plugin-next": {
@@ -5397,9 +5436,9 @@
} }
}, },
"node_modules/@next/swc-darwin-arm64": { "node_modules/@next/swc-darwin-arm64": {
"version": "16.1.6", "version": "16.2.1",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz", "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.1.tgz",
"integrity": "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==", "integrity": "sha512-BwZ8w8YTaSEr2HIuXLMLxIdElNMPvY9fLqb20LX9A9OMGtJilhHLbCL3ggyd0TwjmMcTxi0XXt+ur1vWUoxj2Q==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -5413,9 +5452,9 @@
} }
}, },
"node_modules/@next/swc-darwin-x64": { "node_modules/@next/swc-darwin-x64": {
"version": "16.1.6", "version": "16.2.1",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz", "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.1.tgz",
"integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==", "integrity": "sha512-/vrcE6iQSJq3uL3VGVHiXeaKbn8Es10DGTGRJnRZlkNQQk3kaNtAJg8Y6xuAlrx/6INKVjkfi5rY0iEXorZ6uA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -5429,9 +5468,9 @@
} }
}, },
"node_modules/@next/swc-linux-arm64-gnu": { "node_modules/@next/swc-linux-arm64-gnu": {
"version": "16.1.6", "version": "16.2.1",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz", "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.1.tgz",
"integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==", "integrity": "sha512-uLn+0BK+C31LTVbQ/QU+UaVrV0rRSJQ8RfniQAHPghDdgE+SlroYqcmFnO5iNjNfVWCyKZHYrs3Nl0mUzWxbBw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -5445,9 +5484,9 @@
} }
}, },
"node_modules/@next/swc-linux-arm64-musl": { "node_modules/@next/swc-linux-arm64-musl": {
"version": "16.1.6", "version": "16.2.1",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz", "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.1.tgz",
"integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==", "integrity": "sha512-ssKq6iMRnHdnycGp9hCuGnXJZ0YPr4/wNwrfE5DbmvEcgl9+yv97/Kq3TPVDfYome1SW5geciLB9aiEqKXQjlQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -5461,9 +5500,9 @@
} }
}, },
"node_modules/@next/swc-linux-x64-gnu": { "node_modules/@next/swc-linux-x64-gnu": {
"version": "16.1.6", "version": "16.2.1",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz", "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.1.tgz",
"integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==", "integrity": "sha512-HQm7SrHRELJ30T1TSmT706IWovFFSRGxfgUkyWJZF/RKBMdbdRWJuFrcpDdE5vy9UXjFOx6L3mRdqH04Mmx0hg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -5477,9 +5516,9 @@
} }
}, },
"node_modules/@next/swc-linux-x64-musl": { "node_modules/@next/swc-linux-x64-musl": {
"version": "16.1.6", "version": "16.2.1",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz", "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.1.tgz",
"integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==", "integrity": "sha512-aV2iUaC/5HGEpbBkE+4B8aHIudoOy5DYekAKOMSHoIYQ66y/wIVeaRx8MS2ZMdxe/HIXlMho4ubdZs/J8441Tg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -5493,9 +5532,9 @@
} }
}, },
"node_modules/@next/swc-win32-arm64-msvc": { "node_modules/@next/swc-win32-arm64-msvc": {
"version": "16.1.6", "version": "16.2.1",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz", "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.1.tgz",
"integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==", "integrity": "sha512-IXdNgiDHaSk0ZUJ+xp0OQTdTgnpx1RCfRTalhn3cjOP+IddTMINwA7DXZrwTmGDO8SUr5q2hdP/du4DcrB1GxA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -5509,9 +5548,9 @@
} }
}, },
"node_modules/@next/swc-win32-x64-msvc": { "node_modules/@next/swc-win32-x64-msvc": {
"version": "16.1.6", "version": "16.2.1",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz", "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.1.tgz",
"integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==", "integrity": "sha512-qvU+3a39Hay+ieIztkGSbF7+mccbbg1Tk25hc4JDylf8IHjYmY/Zm64Qq1602yPyQqvie+vf5T/uPwNxDNIoeg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -7017,16 +7056,6 @@
} }
} }
}, },
"node_modules/@trysound/sax": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
"integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/@turf/along": { "node_modules/@turf/along": {
"version": "7.2.0", "version": "7.2.0",
"resolved": "https://registry.npmjs.org/@turf/along/-/along-7.2.0.tgz", "resolved": "https://registry.npmjs.org/@turf/along/-/along-7.2.0.tgz",
@@ -9660,13 +9689,13 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
"version": "9.0.5", "version": "9.0.9",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
"dev": true, "dev": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"brace-expansion": "^2.0.1" "brace-expansion": "^2.0.2"
}, },
"engines": { "engines": {
"node": ">=16 || 14 >=14.17" "node": ">=16 || 14 >=14.17"
@@ -10053,9 +10082,9 @@
} }
}, },
"node_modules/ajv": { "node_modules/ajv": {
"version": "8.17.1", "version": "8.18.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.3", "fast-deep-equal": "^3.1.3",
@@ -10442,13 +10471,13 @@
} }
}, },
"node_modules/axios": { "node_modules/axios": {
"version": "1.12.2", "version": "1.13.6",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz",
"integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", "integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"follow-redirects": "^1.15.6", "follow-redirects": "^1.15.11",
"form-data": "^4.0.4", "form-data": "^4.0.5",
"proxy-from-env": "^1.1.0" "proxy-from-env": "^1.1.0"
} }
}, },
@@ -12219,9 +12248,9 @@
} }
}, },
"node_modules/detect-libc": { "node_modules/detect-libc": {
"version": "2.1.1", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.1.tgz", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
"integrity": "sha512-ecqj/sy1jcK1uWrwpR67UhYrIFQ+5WlGxth34WquCbamhFA6hkkwiu37o6J5xCHdo1oixJRfVRw+ywV+Hq/0Aw==", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"engines": { "engines": {
"node": ">=8" "node": ">=8"
@@ -13131,9 +13160,9 @@
} }
}, },
"node_modules/eslint/node_modules/ajv": { "node_modules/eslint/node_modules/ajv": {
"version": "6.12.6", "version": "6.14.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -13453,10 +13482,10 @@
], ],
"license": "BSD-3-Clause" "license": "BSD-3-Clause"
}, },
"node_modules/fast-xml-parser": { "node_modules/fast-xml-builder": {
"version": "5.3.4", "version": "1.1.4",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.4.tgz", "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.4.tgz",
"integrity": "sha512-EFd6afGmXlCx8H8WTZHhAoDaWaGyuIBoZJ2mknrNxug+aZKjkp0a0dlars9Izl+jF+7Gu1/5f/2h68cQpe0IiA==", "integrity": "sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==",
"funding": [ "funding": [
{ {
"type": "github", "type": "github",
@@ -13465,7 +13494,24 @@
], ],
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"strnum": "^2.1.0" "path-expression-matcher": "^1.1.3"
}
},
"node_modules/fast-xml-parser": {
"version": "5.5.9",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.5.9.tgz",
"integrity": "sha512-jldvxr1MC6rtiZKgrFnDSvT8xuH+eJqxqOBThUVjYrxssYTo1avZLGql5l0a0BAERR01CadYzZ83kVEkbyDg+g==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/NaturalIntelligence"
}
],
"license": "MIT",
"dependencies": {
"fast-xml-builder": "^1.1.4",
"path-expression-matcher": "^1.2.0",
"strnum": "^2.2.2"
}, },
"bin": { "bin": {
"fxparser": "src/cli/cli.js" "fxparser": "src/cli/cli.js"
@@ -13754,9 +13800,9 @@
} }
}, },
"node_modules/flatted": { "node_modules/flatted": {
"version": "3.3.3", "version": "3.4.2",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
@@ -13834,9 +13880,9 @@
} }
}, },
"node_modules/form-data": { "node_modules/form-data": {
"version": "4.0.4", "version": "4.0.5",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"asynckit": "^0.4.0", "asynckit": "^0.4.0",
@@ -13858,6 +13904,33 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/framer-motion": {
"version": "12.38.0",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.38.0.tgz",
"integrity": "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g==",
"license": "MIT",
"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"
},
"peerDependenciesMeta": {
"@emotion/is-prop-valid": {
"optional": true
},
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
"node_modules/fresh": { "node_modules/fresh": {
"version": "0.5.2", "version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
@@ -14158,12 +14231,12 @@
} }
}, },
"node_modules/glob/node_modules/minimatch": { "node_modules/glob/node_modules/minimatch": {
"version": "9.0.5", "version": "9.0.9",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"brace-expansion": "^2.0.1" "brace-expansion": "^2.0.2"
}, },
"engines": { "engines": {
"node": ">=16 || 14 >=14.17" "node": ">=16 || 14 >=14.17"
@@ -17941,9 +18014,9 @@
} }
}, },
"node_modules/minimatch": { "node_modules/minimatch": {
"version": "3.1.2", "version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
@@ -18021,6 +18094,21 @@
"node": "*" "node": "*"
} }
}, },
"node_modules/motion-dom": {
"version": "12.38.0",
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.38.0.tgz",
"integrity": "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA==",
"license": "MIT",
"dependencies": {
"motion-utils": "^12.36.0"
}
},
"node_modules/motion-utils": {
"version": "12.36.0",
"resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.36.0.tgz",
"integrity": "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg==",
"license": "MIT"
},
"node_modules/ms": { "node_modules/ms": {
"version": "2.1.3", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -18090,14 +18178,14 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/next": { "node_modules/next": {
"version": "16.1.6", "version": "16.2.1",
"resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz", "resolved": "https://registry.npmjs.org/next/-/next-16.2.1.tgz",
"integrity": "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==", "integrity": "sha512-VaChzNL7o9rbfdt60HUj8tev4m6d7iC1igAy157526+cJlXOQu5LzsBXNT+xaJnTP/k+utSX5vMv7m0G+zKH+Q==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@next/env": "16.1.6", "@next/env": "16.2.1",
"@swc/helpers": "0.5.15", "@swc/helpers": "0.5.15",
"baseline-browser-mapping": "^2.8.3", "baseline-browser-mapping": "^2.9.19",
"caniuse-lite": "^1.0.30001579", "caniuse-lite": "^1.0.30001579",
"postcss": "8.4.31", "postcss": "8.4.31",
"styled-jsx": "5.1.6" "styled-jsx": "5.1.6"
@@ -18109,15 +18197,15 @@
"node": ">=20.9.0" "node": ">=20.9.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"@next/swc-darwin-arm64": "16.1.6", "@next/swc-darwin-arm64": "16.2.1",
"@next/swc-darwin-x64": "16.1.6", "@next/swc-darwin-x64": "16.2.1",
"@next/swc-linux-arm64-gnu": "16.1.6", "@next/swc-linux-arm64-gnu": "16.2.1",
"@next/swc-linux-arm64-musl": "16.1.6", "@next/swc-linux-arm64-musl": "16.2.1",
"@next/swc-linux-x64-gnu": "16.1.6", "@next/swc-linux-x64-gnu": "16.2.1",
"@next/swc-linux-x64-musl": "16.1.6", "@next/swc-linux-x64-musl": "16.2.1",
"@next/swc-win32-arm64-msvc": "16.1.6", "@next/swc-win32-arm64-msvc": "16.2.1",
"@next/swc-win32-x64-msvc": "16.1.6", "@next/swc-win32-x64-msvc": "16.2.1",
"sharp": "^0.34.4" "sharp": "^0.34.5"
}, },
"peerDependencies": { "peerDependencies": {
"@opentelemetry/api": "^1.1.0", "@opentelemetry/api": "^1.1.0",
@@ -18920,6 +19008,21 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/path-expression-matcher": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.2.0.tgz",
"integrity": "sha512-DwmPWeFn+tq7TiyJ2CxezCAirXjFxvaiD03npak3cRjlP9+OjTmSy1EpIrEbh+l6JgUundniloMLDQ/6VTdhLQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/NaturalIntelligence"
}
],
"license": "MIT",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/path-is-absolute": { "node_modules/path-is-absolute": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
@@ -19433,9 +19536,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/qs": { "node_modules/qs": {
"version": "6.14.1", "version": "6.14.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
"integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"side-channel": "^1.1.0" "side-channel": "^1.1.0"
@@ -20273,6 +20376,16 @@
"postcss": "^8.3.11" "postcss": "^8.3.11"
} }
}, },
"node_modules/sax": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz",
"integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==",
"dev": true,
"license": "BlueOak-1.0.0",
"engines": {
"node": ">=11.0.0"
}
},
"node_modules/saxes": { "node_modules/saxes": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
@@ -20603,16 +20716,16 @@
} }
}, },
"node_modules/sharp": { "node_modules/sharp": {
"version": "0.34.4", "version": "0.34.5",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.4.tgz", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz",
"integrity": "sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA==", "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==",
"hasInstallScript": true, "hasInstallScript": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"optional": true, "optional": true,
"dependencies": { "dependencies": {
"@img/colour": "^1.0.0", "@img/colour": "^1.0.0",
"detect-libc": "^2.1.0", "detect-libc": "^2.1.2",
"semver": "^7.7.2" "semver": "^7.7.3"
}, },
"engines": { "engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0" "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
@@ -20621,34 +20734,36 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
}, },
"optionalDependencies": { "optionalDependencies": {
"@img/sharp-darwin-arm64": "0.34.4", "@img/sharp-darwin-arm64": "0.34.5",
"@img/sharp-darwin-x64": "0.34.4", "@img/sharp-darwin-x64": "0.34.5",
"@img/sharp-libvips-darwin-arm64": "1.2.3", "@img/sharp-libvips-darwin-arm64": "1.2.4",
"@img/sharp-libvips-darwin-x64": "1.2.3", "@img/sharp-libvips-darwin-x64": "1.2.4",
"@img/sharp-libvips-linux-arm": "1.2.3", "@img/sharp-libvips-linux-arm": "1.2.4",
"@img/sharp-libvips-linux-arm64": "1.2.3", "@img/sharp-libvips-linux-arm64": "1.2.4",
"@img/sharp-libvips-linux-ppc64": "1.2.3", "@img/sharp-libvips-linux-ppc64": "1.2.4",
"@img/sharp-libvips-linux-s390x": "1.2.3", "@img/sharp-libvips-linux-riscv64": "1.2.4",
"@img/sharp-libvips-linux-x64": "1.2.3", "@img/sharp-libvips-linux-s390x": "1.2.4",
"@img/sharp-libvips-linuxmusl-arm64": "1.2.3", "@img/sharp-libvips-linux-x64": "1.2.4",
"@img/sharp-libvips-linuxmusl-x64": "1.2.3", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4",
"@img/sharp-linux-arm": "0.34.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4",
"@img/sharp-linux-arm64": "0.34.4", "@img/sharp-linux-arm": "0.34.5",
"@img/sharp-linux-ppc64": "0.34.4", "@img/sharp-linux-arm64": "0.34.5",
"@img/sharp-linux-s390x": "0.34.4", "@img/sharp-linux-ppc64": "0.34.5",
"@img/sharp-linux-x64": "0.34.4", "@img/sharp-linux-riscv64": "0.34.5",
"@img/sharp-linuxmusl-arm64": "0.34.4", "@img/sharp-linux-s390x": "0.34.5",
"@img/sharp-linuxmusl-x64": "0.34.4", "@img/sharp-linux-x64": "0.34.5",
"@img/sharp-wasm32": "0.34.4", "@img/sharp-linuxmusl-arm64": "0.34.5",
"@img/sharp-win32-arm64": "0.34.4", "@img/sharp-linuxmusl-x64": "0.34.5",
"@img/sharp-win32-ia32": "0.34.4", "@img/sharp-wasm32": "0.34.5",
"@img/sharp-win32-x64": "0.34.4" "@img/sharp-win32-arm64": "0.34.5",
"@img/sharp-win32-ia32": "0.34.5",
"@img/sharp-win32-x64": "0.34.5"
} }
}, },
"node_modules/sharp/node_modules/semver": { "node_modules/sharp/node_modules/semver": {
"version": "7.7.2", "version": "7.7.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
"license": "ISC", "license": "ISC",
"optional": true, "optional": true,
"bin": { "bin": {
@@ -21237,9 +21352,9 @@
} }
}, },
"node_modules/strnum": { "node_modules/strnum": {
"version": "2.1.2", "version": "2.2.2",
"resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.2.tgz", "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.2.tgz",
"integrity": "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==", "integrity": "sha512-DnR90I+jtXNSTXWdwrEy9FakW7UX+qUZg28gj5fk2vxxl7uS/3bpI4fjFYVmdK9etptYBPNkpahuQnEwhwECqA==",
"funding": [ "funding": [
{ {
"type": "github", "type": "github",
@@ -21334,19 +21449,19 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/svgo": { "node_modules/svgo": {
"version": "3.3.2", "version": "3.3.3",
"resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.3.tgz",
"integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", "integrity": "sha512-+wn7I4p7YgJhHs38k2TNjy1vCfPIfLIJWR5MnCStsN8WuuTcBnRKcMHQLMM2ijxGZmDoZwNv8ipl5aTTen62ng==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@trysound/sax": "0.2.0",
"commander": "^7.2.0", "commander": "^7.2.0",
"css-select": "^5.1.0", "css-select": "^5.1.0",
"css-tree": "^2.3.1", "css-tree": "^2.3.1",
"css-what": "^6.1.0", "css-what": "^6.1.0",
"csso": "^5.0.5", "csso": "^5.0.5",
"picocolors": "^1.0.0" "picocolors": "^1.0.0",
"sax": "^1.5.0"
}, },
"bin": { "bin": {
"svgo": "bin/svgo" "svgo": "bin/svgo"
@@ -21421,9 +21536,9 @@
} }
}, },
"node_modules/tar": { "node_modules/tar": {
"version": "7.5.7", "version": "7.5.13",
"resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz", "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.13.tgz",
"integrity": "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==", "integrity": "sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng==",
"license": "BlueOak-1.0.0", "license": "BlueOak-1.0.0",
"dependencies": { "dependencies": {
"@isaacs/fs-minipass": "^4.0.0", "@isaacs/fs-minipass": "^4.0.0",
+2 -1
View File
@@ -39,6 +39,7 @@
"deck.gl": "^9.1.14", "deck.gl": "^9.1.14",
"echarts": "^6.0.0", "echarts": "^6.0.0",
"echarts-for-react": "^3.0.5", "echarts-for-react": "^3.0.5",
"framer-motion": "^12.38.0",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"next": "^16.1.6", "next": "^16.1.6",
"next-auth": "^4.24.5", "next-auth": "^4.24.5",
@@ -53,7 +54,7 @@
"zustand": "^5.0.11" "zustand": "^5.0.11"
}, },
"overrides": { "overrides": {
"fast-xml-parser": "5.3.4" "fast-xml-parser": "5.5.9"
}, },
"devDependencies": { "devDependencies": {
"@svgr/webpack": "^8.1.0", "@svgr/webpack": "^8.1.0",
+69 -6
View File
@@ -1,14 +1,58 @@
import { NextAuthOptions } from "next-auth"; import { NextAuthOptions } from "next-auth";
import { JWT } from "next-auth/jwt";
import KeycloakProvider from "next-auth/providers/keycloak"; import KeycloakProvider from "next-auth/providers/keycloak";
import Avatar from "@assets/avatar/avatar-small.jpeg"; import Avatar from "@assets/avatar/avatar-small.jpeg";
type KeycloakTokenResponse = {
access_token: string;
expires_in: number;
refresh_token?: string;
};
const keycloakIssuer = process.env.KEYCLOAK_ISSUER!;
const keycloakClientId = process.env.KEYCLOAK_CLIENT_ID!;
const keycloakClientSecret = process.env.KEYCLOAK_CLIENT_SECRET!;
const keycloakTokenEndpoint = `${keycloakIssuer.replace(/\/$/, "")}/protocol/openid-connect/token`;
const refreshAccessToken = async (token: JWT): Promise<JWT> => {
if (!token.refreshToken) {
return { ...token, error: "RefreshAccessTokenError" };
}
const body = new URLSearchParams({
grant_type: "refresh_token",
client_id: keycloakClientId,
client_secret: keycloakClientSecret,
refresh_token: token.refreshToken,
});
const response = await fetch(keycloakTokenEndpoint, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body,
});
const refreshed = (await response.json()) as KeycloakTokenResponse;
if (!response.ok || !refreshed.access_token || typeof refreshed.expires_in !== "number") {
return { ...token, error: "RefreshAccessTokenError" };
}
return {
...token,
accessToken: refreshed.access_token,
accessTokenExpires: Date.now() + refreshed.expires_in * 1000,
refreshToken: refreshed.refresh_token ?? token.refreshToken,
error: undefined,
};
};
const authOptions: NextAuthOptions = { const authOptions: NextAuthOptions = {
// Configure one or more authentication providers // Configure one or more authentication providers
providers: [ providers: [
KeycloakProvider({ KeycloakProvider({
clientId: process.env.KEYCLOAK_CLIENT_ID!, clientId: keycloakClientId,
clientSecret: process.env.KEYCLOAK_CLIENT_SECRET!, clientSecret: keycloakClientSecret,
issuer: process.env.KEYCLOAK_ISSUER!, issuer: keycloakIssuer,
profile(profile) { profile(profile) {
return { return {
id: profile.sub, id: profile.sub,
@@ -25,10 +69,26 @@ const authOptions: NextAuthOptions = {
if (profile?.sub) { if (profile?.sub) {
token.sub = profile.sub; token.sub = profile.sub;
} }
if (account?.access_token) {
token.accessToken = account.access_token; if (account) {
if (account.access_token) {
token.accessToken = account.access_token;
}
if (account.refresh_token) {
token.refreshToken = account.refresh_token;
}
if (typeof account.expires_at === "number") {
token.accessTokenExpires = account.expires_at * 1000;
}
token.error = undefined;
return token;
} }
return token;
if (typeof token.accessTokenExpires === "number" && Date.now() < token.accessTokenExpires - 30_000) {
return token;
}
return refreshAccessToken(token);
}, },
session: async ({ session, token }) => { session: async ({ session, token }) => {
if (session.user && token.sub) { if (session.user && token.sub) {
@@ -37,6 +97,9 @@ const authOptions: NextAuthOptions = {
if (token.accessToken) { if (token.accessToken) {
session.accessToken = token.accessToken; session.accessToken = token.accessToken;
} }
if (token.error) {
session.error = token.error;
}
return session; return session;
}, },
}, },
+426 -89
View File
@@ -1,23 +1,35 @@
"use client"; "use client";
import ChatOutlined from "@mui/icons-material/ChatOutlined"; import React, { useMemo, useRef, useState, useEffect } from "react";
import Close from "@mui/icons-material/Close"; import ReactMarkdown from "react-markdown";
import Send from "@mui/icons-material/Send"; import { motion, AnimatePresence } from "framer-motion";
// MUI
import { import {
Avatar,
Box, Box,
CircularProgress,
Drawer, Drawer,
IconButton, IconButton,
List, Paper,
ListItem,
ListItemText,
Stack, Stack,
TextField, TextField,
Typography, Typography,
useTheme,
alpha,
Tooltip,
} from "@mui/material"; } from "@mui/material";
import React, { useMemo, useRef, useState } from "react";
// Icons
import CloseRounded from "@mui/icons-material/CloseRounded";
import SendRounded from "@mui/icons-material/SendRounded";
import StopRounded from "@mui/icons-material/StopRounded";
import AutoAwesome from "@mui/icons-material/AutoAwesome"; // Sparkle icon for AI
import PersonRounded from "@mui/icons-material/PersonRounded";
// Logic
import { streamCopilotChat } from "@/lib/chatStream"; import { streamCopilotChat } from "@/lib/chatStream";
// Types
type Message = { type Message = {
id: string; id: string;
role: "user" | "assistant"; role: "user" | "assistant";
@@ -29,17 +41,87 @@ type Props = {
onClose: () => void; onClose: () => void;
}; };
// Utils
const createId = () => `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`; const createId = () => `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
// --- Components ---
const TypingIndicator = () => {
return (
<Stack direction="row" spacing={0.5} alignItems="center" sx={{ p: 1 }}>
{[0, 1, 2].map((i) => (
<motion.div
key={i}
initial={{ y: 0 }}
animate={{ y: [-4, 4, -4] }}
transition={{
duration: 0.6,
repeat: Infinity,
delay: i * 0.15,
ease: "easeInOut", // Smooth sine wave
}}
>
<Box
sx={{
width: 8,
height: 8,
borderRadius: "50%",
background: "linear-gradient(135deg, #FF6B6B 0%, #FF8E53 100%)", // Warm gradient dots
}}
/>
</motion.div>
))}
</Stack>
);
};
// Animated Background Blob
const Blob = ({ color, size, top, left, delay }: { color: string; size: number; top: string; left: string; delay: number }) => (
<motion.div
initial={{ scale: 0.8, opacity: 0.3, x: 0, y: 0 }}
animate={{
scale: [0.8, 1.2, 0.8],
opacity: [0.3, 0.5, 0.3],
x: [0, 30, 0],
y: [0, -30, 0],
}}
transition={{
duration: 8,
repeat: Infinity,
ease: "easeInOut",
delay: delay,
}}
style={{
position: "absolute",
top,
left,
width: size,
height: size,
borderRadius: "50%",
background: color,
filter: "blur(60px)",
zIndex: 0,
pointerEvents: "none",
}}
/>
);
export const GlobalChatbox: React.FC<Props> = ({ open, onClose }) => { export const GlobalChatbox: React.FC<Props> = ({ open, onClose }) => {
const [messages, setMessages] = useState<Message[]>([]); const [messages, setMessages] = useState<Message[]>([]);
const [input, setInput] = useState(""); const [input, setInput] = useState("");
const [isStreaming, setIsStreaming] = useState(false); const [isStreaming, setIsStreaming] = useState(false);
const [conversationId, setConversationId] = useState<string | undefined>(undefined); const [conversationId, setConversationId] = useState<string | undefined>(undefined);
const abortRef = useRef<AbortController | null>(null); const abortRef = useRef<AbortController | null>(null);
const bottomRef = useRef<HTMLDivElement>(null);
const theme = useTheme();
const canSend = useMemo(() => input.trim().length > 0 && !isStreaming, [input, isStreaming]); const canSend = useMemo(() => input.trim().length > 0 && !isStreaming, [input, isStreaming]);
// Auto-scroll
useEffect(() => {
bottomRef.current?.scrollIntoView({ behavior: "smooth" });
}, [messages, isStreaming]);
const handleSend = async () => { const handleSend = async () => {
const prompt = input.trim(); const prompt = input.trim();
if (!prompt || isStreaming) return; if (!prompt || isStreaming) return;
@@ -65,45 +147,31 @@ export const GlobalChatbox: React.FC<Props> = ({ open, onClose }) => {
signal: controller.signal, signal: controller.signal,
onEvent: (event) => { onEvent: (event) => {
if (event.type === "token") { if (event.type === "token") {
if (!conversationId && event.conversationId) { if (!conversationId && event.conversationId) setConversationId(event.conversationId);
setConversationId(event.conversationId);
}
setMessages((prev) => setMessages((prev) =>
prev.map((item) => prev.map((m) =>
item.id === assistantId m.id === assistantId ? { ...m, content: m.content + event.content } : m
? { ...item, content: `${item.content}${event.content}` } )
: item,
),
); );
} else if (event.type === "done") { } else if (event.type === "done") {
if (!conversationId && event.conversationId) { if (!conversationId && event.conversationId) setConversationId(event.conversationId);
setConversationId(event.conversationId);
}
setIsStreaming(false); setIsStreaming(false);
} else if (event.type === "error") { } else if (event.type === "error") {
setMessages((prev) => setMessages((prev) =>
prev.map((item) => prev.map((m) =>
item.id === assistantId m.id === assistantId
? { ? { ...m, content: m.content || `错误:${event.message}` }
...item, : m
content: )
item.content ||
`Error: ${event.message}${event.detail ? ` (${event.detail})` : ""}`,
}
: item,
),
); );
setIsStreaming(false); setIsStreaming(false);
} }
}, },
}); });
} catch (error) { } catch (error) {
if (abortRef.current?.signal.aborted) return;
setMessages((prev) => setMessages((prev) =>
prev.map((item) => prev.map((m) => (m.id === assistantId ? { ...m, content: `错误:${String(error)}` } : m))
item.id === assistantId
? { ...item, content: `Error: ${String(error)}` }
: item,
),
); );
setIsStreaming(false); setIsStreaming(false);
} finally { } finally {
@@ -118,66 +186,335 @@ export const GlobalChatbox: React.FC<Props> = ({ open, onClose }) => {
}; };
return ( return (
<Drawer anchor="right" open={open} onClose={onClose}> <Drawer
<Box sx={{ width: { xs: "100vw", sm: 420 }, height: "100%", display: "flex", flexDirection: "column" }}> anchor="right"
<Stack direction="row" alignItems="center" justifyContent="space-between" sx={{ p: 2, borderBottom: "1px solid", borderColor: "divider" }}> open={open}
<Stack direction="row" alignItems="center" spacing={1}> onClose={onClose}
<ChatOutlined /> sx={{ zIndex: (muiTheme) => muiTheme.zIndex.modal + 100 }}
<Typography variant="subtitle1" fontWeight={600}> PaperProps={{
Copilot Chat sx: {
</Typography> width: { xs: "100%", sm: 480 },
background: "transparent",
boxShadow: "none",
overflow: "hidden", // Clip blobs
zIndex: (muiTheme) => muiTheme.zIndex.modal + 100,
},
}}
ModalProps={{
BackdropProps: {
sx: { backdropFilter: "blur(6px)", bgcolor: alpha(theme.palette.background.default, 0.3) },
},
}}
>
<Box
sx={{
height: "100%",
display: "flex",
flexDirection: "column",
bgcolor: alpha("#fff", 0.75), // Light glass base
backdropFilter: "blur(30px)",
position: "relative",
}}
>
{/* Ambient Blobs */}
<Blob color={alpha(theme.palette.primary.main, 0.3)} size={300} top="-10%" left="-20%" delay={0} />
<Blob color={alpha(theme.palette.secondary.main, 0.3)} size={250} top="40%" left="60%" delay={2} />
<Blob color={alpha(theme.palette.success.light, 0.2)} size={200} top="80%" left="-10%" delay={4} />
{/* Header - Transparent & Floating */}
<Box
sx={{
p: 3,
zIndex: 10,
display: "flex",
alignItems: "center",
justifyContent: "space-between",
}}
>
<Stack direction="row" alignItems="center" spacing={2}>
<motion.div
whileHover={{ rotate: 10, scale: 1.1 }}
whileTap={{ scale: 0.95 }}
>
<Box sx={{ position: "relative" }}>
<Avatar
sx={{
background: `linear-gradient(135deg, ${theme.palette.primary.light}, ${theme.palette.primary.main})`,
boxShadow: `0 8px 20px ${alpha(theme.palette.primary.main, 0.4)}`,
width: 48,
height: 48,
}}
>
<AutoAwesome fontSize="medium" sx={{ color: "#fff" }} />
</Avatar>
<Box
sx={{
position: "absolute",
bottom: 2,
right: 2,
width: 12,
height: 12,
bgcolor: "success.main",
borderRadius: "50%",
border: "2px solid #fff",
boxShadow: "0 0 0 2px rgba(255,255,255,0.5)"
}}
/>
</Box>
</motion.div>
<Box>
<Typography variant="h6" fontWeight={800} sx={{ background: `linear-gradient(90deg, ${theme.palette.primary.dark}, ${theme.palette.secondary.dark})`, backgroundClip: "text", color: "transparent", letterSpacing: -0.5 }}>
Copilot
</Typography>
<Typography variant="caption" color="text.secondary" fontWeight={500}>
AI
</Typography>
</Box>
</Stack> </Stack>
<IconButton onClick={onClose} size="small">
<Close />
</IconButton>
</Stack>
<List sx={{ flex: 1, overflow: "auto", px: 1.5 }}> <motion.div whileHover={{ scale: 1.1, rotate: 90 }} whileTap={{ scale: 0.9 }}>
{messages.map((message) => ( <IconButton onClick={onClose} size="small" sx={{ color: "text.primary", bgcolor: alpha("#fff", 0.5), "&:hover": { bgcolor: "#fff" } }}>
<ListItem key={message.id} sx={{ justifyContent: message.role === "user" ? "flex-end" : "flex-start" }}> <CloseRounded />
<Box </IconButton>
</motion.div>
</Box>
{/* Messages - Bouncy List */}
<Box sx={{ flex: 1, overflowY: "auto", px: 2.5, py: 2, display: "flex", flexDirection: "column", gap: 2.5, zIndex: 5 }}>
<AnimatePresence initial={false}>
{messages.length === 0 && (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ type: "spring", stiffness: 200, damping: 20 }}
style={{ margin: "auto", width: "100%" }}
>
<Paper
elevation={0}
sx={{
p: 4,
borderRadius: 6,
bgcolor: alpha("#fff", 0.6),
border: `1px solid ${alpha(theme.palette.divider, 0.1)}`,
maxWidth: 320,
mx: "auto",
textAlign: "center",
backdropFilter: "blur(10px)",
}}
>
<motion.div
animate={{ y: [-5, 5, -5] }}
transition={{ duration: 4, repeat: Infinity, ease: "easeInOut" }}
>
<AutoAwesome sx={{ fontSize: 56, color: "primary.main", mb: 2, filter: "drop-shadow(0 4px 8px rgba(0,0,0,0.1))" }} />
</motion.div>
<Typography variant="h6" color="text.primary" fontWeight={700} gutterBottom>
👋
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ lineHeight: 1.6 }}>
</Typography>
</Paper>
</motion.div>
)}
{messages.map((message) => {
const isUser = message.role === "user";
return (
<motion.div
key={message.id}
initial={{ opacity: 0, scale: 0.8, x: isUser ? 50 : -50 }}
animate={{ opacity: 1, scale: 1, x: 0 }}
exit={{ opacity: 0, scale: 0.8 }}
transition={{ type: "spring", stiffness: 350, damping: 25 }}
style={{
alignSelf: isUser ? "flex-end" : "flex-start",
maxWidth: "85%",
display: "flex",
flexDirection: isUser ? "row-reverse" : "row",
gap: 12,
alignItems: "flex-end",
}}
>
{!isUser && (
<Avatar sx={{ width: 28, height: 28, bgcolor: alpha(theme.palette.secondary.main, 0.1), mb: 0.5 }}>
<AutoAwesome sx={{ fontSize: 16, color: "secondary.main" }} />
</Avatar>
)}
<Paper
elevation={isUser ? 8 : 2}
sx={{
p: 2.5,
borderRadius: 4,
borderBottomRightRadius: isUser ? 4 : 24,
borderBottomLeftRadius: !isUser ? 4 : 24,
bgcolor: isUser ? "primary.main" : "#fff",
color: isUser ? "#fff" : "text.primary",
background: isUser ? `linear-gradient(135deg, ${theme.palette.primary.main}, ${theme.palette.primary.dark})` : undefined,
boxShadow: isUser
? `0 8px 24px -4px ${alpha(theme.palette.primary.main, 0.5)}`
: `0 4px 16px -4px ${alpha("#000", 0.05)}`,
// Markdown Styles
"& p": { m: 0, lineHeight: 1.6 },
"& code": {
fontFamily: "monospace",
bgcolor: isUser ? "rgba(255,255,255,0.2)" : alpha(theme.palette.grey[100], 0.8),
px: 0.8,
py: 0.2,
borderRadius: 1,
fontSize: "0.85em",
border: isUser ? "none" : `1px solid ${alpha(theme.palette.divider, 0.1)}`,
},
"& pre": {
bgcolor: isUser ? "rgba(0,0,0,0.25)" : "#222",
color: "#f8f8f2",
p: 2,
borderRadius: 3,
overflowX: "auto",
my: 1.5,
fontSize: "0.85em",
border: "1px solid rgba(255,255,255,0.1)",
},
"& ul, & ol": { pl: 2.5, my: 1 },
}}
>
{isUser ? (
<Typography variant="body2" fontSize="0.95rem" sx={{ whiteSpace: "pre-wrap" }}>{message.content}</Typography>
) : (
<ReactMarkdown>{message.content || "..."}</ReactMarkdown>
)}
</Paper>
</motion.div>
);
})}
</AnimatePresence>
{isStreaming && (
<motion.div
initial={{ opacity: 0, y: 10, scale: 0.9 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
transition={{ type: "spring", stiffness: 300 }}
style={{ alignSelf: "flex-start", display: "flex", gap: 12, marginTop: 4, marginLeft: 40 }}
>
<Paper
elevation={0}
sx={{
p: 1.5,
borderRadius: 4,
bgcolor: alpha("#fff", 0.8),
boxShadow: `0 4px 12px ${alpha("#000", 0.05)}`
}}
>
<TypingIndicator />
</Paper>
</motion.div>
)}
<div ref={bottomRef} style={{ height: 1 }} />
</Box>
{/* Input Area - Floating Capsule */}
<Box sx={{ p: 3, zIndex: 10 }}>
<motion.div
initial={{ y: 20, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ delay: 0.2 }}
>
<Stack
direction="row"
alignItems="center"
component={Paper}
elevation={12}
sx={{ sx={{
maxWidth: "86%", p: "6px 8px",
px: 1.5, borderRadius: 50, // Full capsule
py: 1, bgcolor: alpha("#fff", 0.9),
borderRadius: 2, backdropFilter: "blur(10px)",
bgcolor: message.role === "user" ? "primary.main" : "grey.100", border: `1px solid ${alpha("#fff", 0.6)}`,
color: message.role === "user" ? "primary.contrastText" : "text.primary", boxShadow: `0 12px 40px -8px ${alpha(theme.palette.primary.main, 0.15)}`,
whiteSpace: "pre-wrap", transition: "all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1)",
"&:hover": {
transform: "translateY(-2px)",
boxShadow: `0 16px 48px -8px ${alpha(theme.palette.primary.main, 0.25)}`,
}
}} }}
> >
<ListItemText primaryTypographyProps={{ variant: "body2" }} primary={message.content || "..."} /> <TextField
</Box> value={input}
</ListItem> onChange={(e) => setInput(e.target.value)}
))} onKeyDown={(e) => {
</List> if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
void handleSend();
}
}}
placeholder="输入消息给 Copilot..."
fullWidth
multiline
maxRows={3}
variant="standard"
InputProps={{
disableUnderline: true,
sx: { px: 2.5, py: 1.5, fontSize: "1rem" },
}}
/>
<Stack direction="row" spacing={1} sx={{ p: 1.5, borderTop: "1px solid", borderColor: "divider" }}> <Box sx={{ pr: 0.5 }}>
<TextField <AnimatePresence mode="wait">
value={input} {isStreaming ? (
onChange={(e) => setInput(e.target.value)} <motion.div
onKeyDown={(e) => { key="stop"
if (e.key === "Enter" && !e.shiftKey) { initial={{ scale: 0, rotate: -180 }}
e.preventDefault(); animate={{ scale: 1, rotate: 0 }}
void handleSend(); exit={{ scale: 0, rotate: 180 }}
} transition={{ type: "spring", stiffness: 400, damping: 25 }}
}} >
size="small" <IconButton
multiline onClick={handleAbort}
maxRows={4} sx={{
fullWidth bgcolor: alpha(theme.palette.error.main, 0.1),
placeholder="输入消息..." color: "error.main",
/> width: 44, height: 44,
{isStreaming ? ( "&:hover": { bgcolor: alpha(theme.palette.error.main, 0.2) }
<IconButton color="warning" onClick={handleAbort}> }}
<CircularProgress size={20} /> >
</IconButton> <StopRounded />
) : ( </IconButton>
<IconButton color="primary" disabled={!canSend} onClick={() => void handleSend()}> </motion.div>
<Send /> ) : (
</IconButton> <motion.div
)} key="send"
</Stack> initial={{ scale: 0 }}
animate={{ scale: 1 }}
exit={{ scale: 0 }}
transition={{ type: "spring", stiffness: 400, damping: 25 }}
>
<IconButton
disabled={!canSend}
onClick={() => void handleSend()}
sx={{
bgcolor: canSend ? "primary.main" : "action.disabledBackground",
color: "#fff",
width: 44, height: 44,
transition: "background-color 0.2s",
"&:hover": {
bgcolor: "primary.dark",
boxShadow: `0 4px 12px ${alpha(theme.palette.primary.main, 0.5)}`
}
}}
>
<SendRounded sx={{ ml: 0.5 }} />
</IconButton>
</motion.div>
)}
</AnimatePresence>
</Box>
</Stack>
</motion.div>
</Box>
</Box> </Box>
</Drawer> </Drawer>
); );
+10 -9
View File
@@ -3,6 +3,7 @@
import { ColorModeContext } from "@contexts/color-mode"; import { ColorModeContext } from "@contexts/color-mode";
import DarkModeOutlined from "@mui/icons-material/DarkModeOutlined"; import DarkModeOutlined from "@mui/icons-material/DarkModeOutlined";
import LightModeOutlined from "@mui/icons-material/LightModeOutlined"; import LightModeOutlined from "@mui/icons-material/LightModeOutlined";
import { IoChatbubbleEllipsesOutline } from "react-icons/io5";
import Logout from "@mui/icons-material/Logout"; import Logout from "@mui/icons-material/Logout";
import SwapHoriz from "@mui/icons-material/SwapHoriz"; import SwapHoriz from "@mui/icons-material/SwapHoriz";
import ChatOutlined from "@mui/icons-material/ChatOutlined"; import ChatOutlined from "@mui/icons-material/ChatOutlined";
@@ -94,24 +95,24 @@ export const Header: React.FC<RefineThemedLayoutHeaderProps> = ({
justifyContent="flex-end" justifyContent="flex-end"
alignItems="center" alignItems="center"
> >
<IconButton {/* <IconButton
color="inherit"
onClick={() => setShowChatbox(true)}
>
<ChatOutlined />
</IconButton>
<IconButton
color="inherit" color="inherit"
onClick={() => { onClick={() => {
setMode(); setMode();
}} }}
> >
{mode === "dark" ? <LightModeOutlined /> : <DarkModeOutlined />} {mode === "dark" ? <LightModeOutlined /> : <DarkModeOutlined />}
</IconButton> </IconButton> */}
{(user?.avatar || user?.name) && ( {(user?.avatar || user?.name) && (
<> <>
<IconButton
color="inherit"
onClick={() => setShowChatbox(true)}
sx={{ mr: 1 }}
>
<IoChatbubbleEllipsesOutline />
</IconButton>
<ButtonBase <ButtonBase
onClick={handleMenuOpen} onClick={handleMenuOpen}
sx={{ sx={{
+6 -2
View File
@@ -15,9 +15,13 @@ const resolveUrl = (input: RequestInfo | URL) => {
const isMetaProjectsRequest = (input: RequestInfo | URL) => const isMetaProjectsRequest = (input: RequestInfo | URL) =>
resolveUrl(input).includes("/api/v1/meta/projects"); resolveUrl(input).includes("/api/v1/meta/projects");
export interface ApiFetchInit extends RequestInit {
skipAuthRedirect?: boolean;
}
export const apiFetch = async ( export const apiFetch = async (
input: RequestInfo | URL, input: RequestInfo | URL,
init: RequestInit = {}, init: ApiFetchInit = {},
) => { ) => {
const projectId = useProjectStore.getState().currentProjectId; const projectId = useProjectStore.getState().currentProjectId;
const headers = new Headers(init.headers ?? {}); const headers = new Headers(init.headers ?? {});
@@ -31,7 +35,7 @@ export const apiFetch = async (
const response = await fetch(input, { ...init, headers }); const response = await fetch(input, { ...init, headers });
if (response.status === 401 && typeof window !== "undefined") { if (response.status === 401 && typeof window !== "undefined" && !init.skipAuthRedirect) {
useAuthStore.getState().setAccessToken(null); useAuthStore.getState().setAccessToken(null);
if (!isSigningOut) { if (!isSigningOut) {
isSigningOut = true; isSigningOut = true;
+19
View File
@@ -78,4 +78,23 @@ describe("streamCopilotChat", () => {
{ type: "error", message: "stream request failed", detail: "bad request" }, { type: "error", message: "stream request failed", detail: "bad request" },
]); ]);
}); });
it("emits re-login message on unauthorized response", async () => {
apiFetch.mockResolvedValue({
ok: false,
status: 401,
body: null,
text: async () => "unauthorized",
});
const events: Array<{ type: string; message?: string; detail?: string }> = [];
await streamCopilotChat({
message: "hi",
onEvent: (event) => events.push(event),
});
expect(events).toEqual([
{ type: "error", message: "Login expired. Please sign in again.", detail: undefined },
]);
});
}); });
+11 -2
View File
@@ -49,14 +49,23 @@ export const streamCopilotChat = async ({
message, message,
conversation_id: conversationId, conversation_id: conversationId,
}), }),
skipAuthRedirect: true,
}); });
if (!response.ok || !response.body) { if (!response.ok || !response.body) {
const detail = await response.text(); const detail = await response.text();
let message = "stream request failed";
if (response.status === 403) {
message = "Permission denied. Please contact administrator.";
} else if (response.status === 401) {
message = "Login expired. Please sign in again.";
}
onEvent({ onEvent({
type: "error", type: "error",
message: "stream request failed", message,
detail, detail: (response.status === 403 || response.status === 401) ? undefined : detail,
}); });
return; return;
} }
+4
View File
@@ -4,6 +4,7 @@ import "next-auth/jwt";
declare module "next-auth" { declare module "next-auth" {
interface Session { interface Session {
accessToken?: string; accessToken?: string;
error?: "RefreshAccessTokenError";
user?: { user?: {
id?: string; id?: string;
name?: string | null; name?: string | null;
@@ -21,5 +22,8 @@ declare module "next-auth/jwt" {
interface JWT { interface JWT {
sub?: string; sub?: string;
accessToken?: string; accessToken?: string;
refreshToken?: string;
accessTokenExpires?: number;
error?: "RefreshAccessTokenError";
} }
} }