Spaces:
Running
Running
Jiya3177 commited on
Commit ·
3a376b8
1
Parent(s): aaff8ef
refactor: migrate frontend state to zustand
Browse files- frontend/package-lock.json +48 -124
- frontend/package.json +2 -1
- frontend/src/components/chat/ChatPanel.tsx +18 -22
- frontend/src/components/chat/MessageBubble.tsx +1 -1
- frontend/src/components/chat/SourceCard.tsx +1 -1
- frontend/src/lib/auth.tsx +12 -96
- frontend/src/store/auth-store.ts +124 -0
- frontend/src/store/chat-store.ts +68 -0
frontend/package-lock.json
CHANGED
|
@@ -22,7 +22,8 @@
|
|
| 22 |
"remark-gfm": "^4.0.1",
|
| 23 |
"shadcn": "^4.3.1",
|
| 24 |
"tailwind-merge": "^3.5.0",
|
| 25 |
-
"tw-animate-css": "^1.4.0"
|
|
|
|
| 26 |
},
|
| 27 |
"devDependencies": {
|
| 28 |
"@tailwindcss/postcss": "^4",
|
|
@@ -76,6 +77,7 @@
|
|
| 76 |
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
|
| 77 |
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
| 78 |
"license": "MIT",
|
|
|
|
| 79 |
"dependencies": {
|
| 80 |
"@babel/code-frame": "^7.29.0",
|
| 81 |
"@babel/generator": "^7.29.0",
|
|
@@ -669,6 +671,7 @@
|
|
| 669 |
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
| 670 |
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
| 671 |
"license": "MIT",
|
|
|
|
| 672 |
"engines": {
|
| 673 |
"node": ">=12"
|
| 674 |
},
|
|
@@ -1106,9 +1109,6 @@
|
|
| 1106 |
"cpu": [
|
| 1107 |
"arm"
|
| 1108 |
],
|
| 1109 |
-
"libc": [
|
| 1110 |
-
"glibc"
|
| 1111 |
-
],
|
| 1112 |
"license": "LGPL-3.0-or-later",
|
| 1113 |
"optional": true,
|
| 1114 |
"os": [
|
|
@@ -1125,9 +1125,6 @@
|
|
| 1125 |
"cpu": [
|
| 1126 |
"arm64"
|
| 1127 |
],
|
| 1128 |
-
"libc": [
|
| 1129 |
-
"glibc"
|
| 1130 |
-
],
|
| 1131 |
"license": "LGPL-3.0-or-later",
|
| 1132 |
"optional": true,
|
| 1133 |
"os": [
|
|
@@ -1144,9 +1141,6 @@
|
|
| 1144 |
"cpu": [
|
| 1145 |
"ppc64"
|
| 1146 |
],
|
| 1147 |
-
"libc": [
|
| 1148 |
-
"glibc"
|
| 1149 |
-
],
|
| 1150 |
"license": "LGPL-3.0-or-later",
|
| 1151 |
"optional": true,
|
| 1152 |
"os": [
|
|
@@ -1163,9 +1157,6 @@
|
|
| 1163 |
"cpu": [
|
| 1164 |
"riscv64"
|
| 1165 |
],
|
| 1166 |
-
"libc": [
|
| 1167 |
-
"glibc"
|
| 1168 |
-
],
|
| 1169 |
"license": "LGPL-3.0-or-later",
|
| 1170 |
"optional": true,
|
| 1171 |
"os": [
|
|
@@ -1182,9 +1173,6 @@
|
|
| 1182 |
"cpu": [
|
| 1183 |
"s390x"
|
| 1184 |
],
|
| 1185 |
-
"libc": [
|
| 1186 |
-
"glibc"
|
| 1187 |
-
],
|
| 1188 |
"license": "LGPL-3.0-or-later",
|
| 1189 |
"optional": true,
|
| 1190 |
"os": [
|
|
@@ -1201,9 +1189,6 @@
|
|
| 1201 |
"cpu": [
|
| 1202 |
"x64"
|
| 1203 |
],
|
| 1204 |
-
"libc": [
|
| 1205 |
-
"glibc"
|
| 1206 |
-
],
|
| 1207 |
"license": "LGPL-3.0-or-later",
|
| 1208 |
"optional": true,
|
| 1209 |
"os": [
|
|
@@ -1220,9 +1205,6 @@
|
|
| 1220 |
"cpu": [
|
| 1221 |
"arm64"
|
| 1222 |
],
|
| 1223 |
-
"libc": [
|
| 1224 |
-
"musl"
|
| 1225 |
-
],
|
| 1226 |
"license": "LGPL-3.0-or-later",
|
| 1227 |
"optional": true,
|
| 1228 |
"os": [
|
|
@@ -1239,9 +1221,6 @@
|
|
| 1239 |
"cpu": [
|
| 1240 |
"x64"
|
| 1241 |
],
|
| 1242 |
-
"libc": [
|
| 1243 |
-
"musl"
|
| 1244 |
-
],
|
| 1245 |
"license": "LGPL-3.0-or-later",
|
| 1246 |
"optional": true,
|
| 1247 |
"os": [
|
|
@@ -1258,9 +1237,6 @@
|
|
| 1258 |
"cpu": [
|
| 1259 |
"arm"
|
| 1260 |
],
|
| 1261 |
-
"libc": [
|
| 1262 |
-
"glibc"
|
| 1263 |
-
],
|
| 1264 |
"license": "Apache-2.0",
|
| 1265 |
"optional": true,
|
| 1266 |
"os": [
|
|
@@ -1283,9 +1259,6 @@
|
|
| 1283 |
"cpu": [
|
| 1284 |
"arm64"
|
| 1285 |
],
|
| 1286 |
-
"libc": [
|
| 1287 |
-
"glibc"
|
| 1288 |
-
],
|
| 1289 |
"license": "Apache-2.0",
|
| 1290 |
"optional": true,
|
| 1291 |
"os": [
|
|
@@ -1308,9 +1281,6 @@
|
|
| 1308 |
"cpu": [
|
| 1309 |
"ppc64"
|
| 1310 |
],
|
| 1311 |
-
"libc": [
|
| 1312 |
-
"glibc"
|
| 1313 |
-
],
|
| 1314 |
"license": "Apache-2.0",
|
| 1315 |
"optional": true,
|
| 1316 |
"os": [
|
|
@@ -1333,9 +1303,6 @@
|
|
| 1333 |
"cpu": [
|
| 1334 |
"riscv64"
|
| 1335 |
],
|
| 1336 |
-
"libc": [
|
| 1337 |
-
"glibc"
|
| 1338 |
-
],
|
| 1339 |
"license": "Apache-2.0",
|
| 1340 |
"optional": true,
|
| 1341 |
"os": [
|
|
@@ -1358,9 +1325,6 @@
|
|
| 1358 |
"cpu": [
|
| 1359 |
"s390x"
|
| 1360 |
],
|
| 1361 |
-
"libc": [
|
| 1362 |
-
"glibc"
|
| 1363 |
-
],
|
| 1364 |
"license": "Apache-2.0",
|
| 1365 |
"optional": true,
|
| 1366 |
"os": [
|
|
@@ -1383,9 +1347,6 @@
|
|
| 1383 |
"cpu": [
|
| 1384 |
"x64"
|
| 1385 |
],
|
| 1386 |
-
"libc": [
|
| 1387 |
-
"glibc"
|
| 1388 |
-
],
|
| 1389 |
"license": "Apache-2.0",
|
| 1390 |
"optional": true,
|
| 1391 |
"os": [
|
|
@@ -1408,9 +1369,6 @@
|
|
| 1408 |
"cpu": [
|
| 1409 |
"arm64"
|
| 1410 |
],
|
| 1411 |
-
"libc": [
|
| 1412 |
-
"musl"
|
| 1413 |
-
],
|
| 1414 |
"license": "Apache-2.0",
|
| 1415 |
"optional": true,
|
| 1416 |
"os": [
|
|
@@ -1433,9 +1391,6 @@
|
|
| 1433 |
"cpu": [
|
| 1434 |
"x64"
|
| 1435 |
],
|
| 1436 |
-
"libc": [
|
| 1437 |
-
"musl"
|
| 1438 |
-
],
|
| 1439 |
"license": "Apache-2.0",
|
| 1440 |
"optional": true,
|
| 1441 |
"os": [
|
|
@@ -1856,9 +1811,6 @@
|
|
| 1856 |
"cpu": [
|
| 1857 |
"arm64"
|
| 1858 |
],
|
| 1859 |
-
"libc": [
|
| 1860 |
-
"glibc"
|
| 1861 |
-
],
|
| 1862 |
"license": "MIT",
|
| 1863 |
"optional": true,
|
| 1864 |
"os": [
|
|
@@ -1879,9 +1831,6 @@
|
|
| 1879 |
"cpu": [
|
| 1880 |
"arm64"
|
| 1881 |
],
|
| 1882 |
-
"libc": [
|
| 1883 |
-
"musl"
|
| 1884 |
-
],
|
| 1885 |
"license": "MIT",
|
| 1886 |
"optional": true,
|
| 1887 |
"os": [
|
|
@@ -1902,9 +1851,6 @@
|
|
| 1902 |
"cpu": [
|
| 1903 |
"riscv64"
|
| 1904 |
],
|
| 1905 |
-
"libc": [
|
| 1906 |
-
"glibc"
|
| 1907 |
-
],
|
| 1908 |
"license": "MIT",
|
| 1909 |
"optional": true,
|
| 1910 |
"os": [
|
|
@@ -1925,9 +1871,6 @@
|
|
| 1925 |
"cpu": [
|
| 1926 |
"x64"
|
| 1927 |
],
|
| 1928 |
-
"libc": [
|
| 1929 |
-
"glibc"
|
| 1930 |
-
],
|
| 1931 |
"license": "MIT",
|
| 1932 |
"optional": true,
|
| 1933 |
"os": [
|
|
@@ -1948,9 +1891,6 @@
|
|
| 1948 |
"cpu": [
|
| 1949 |
"x64"
|
| 1950 |
],
|
| 1951 |
-
"libc": [
|
| 1952 |
-
"musl"
|
| 1953 |
-
],
|
| 1954 |
"license": "MIT",
|
| 1955 |
"optional": true,
|
| 1956 |
"os": [
|
|
@@ -2072,9 +2012,6 @@
|
|
| 2072 |
"cpu": [
|
| 2073 |
"arm64"
|
| 2074 |
],
|
| 2075 |
-
"libc": [
|
| 2076 |
-
"glibc"
|
| 2077 |
-
],
|
| 2078 |
"license": "MIT",
|
| 2079 |
"optional": true,
|
| 2080 |
"os": [
|
|
@@ -2091,9 +2028,6 @@
|
|
| 2091 |
"cpu": [
|
| 2092 |
"arm64"
|
| 2093 |
],
|
| 2094 |
-
"libc": [
|
| 2095 |
-
"musl"
|
| 2096 |
-
],
|
| 2097 |
"license": "MIT",
|
| 2098 |
"optional": true,
|
| 2099 |
"os": [
|
|
@@ -2110,9 +2044,6 @@
|
|
| 2110 |
"cpu": [
|
| 2111 |
"x64"
|
| 2112 |
],
|
| 2113 |
-
"libc": [
|
| 2114 |
-
"glibc"
|
| 2115 |
-
],
|
| 2116 |
"license": "MIT",
|
| 2117 |
"optional": true,
|
| 2118 |
"os": [
|
|
@@ -2129,9 +2060,6 @@
|
|
| 2129 |
"cpu": [
|
| 2130 |
"x64"
|
| 2131 |
],
|
| 2132 |
-
"libc": [
|
| 2133 |
-
"musl"
|
| 2134 |
-
],
|
| 2135 |
"license": "MIT",
|
| 2136 |
"optional": true,
|
| 2137 |
"os": [
|
|
@@ -2178,6 +2106,7 @@
|
|
| 2178 |
"resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz",
|
| 2179 |
"integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==",
|
| 2180 |
"license": "MIT",
|
|
|
|
| 2181 |
"engines": {
|
| 2182 |
"node": "^14.21.3 || >=16"
|
| 2183 |
},
|
|
@@ -2446,9 +2375,6 @@
|
|
| 2446 |
"arm64"
|
| 2447 |
],
|
| 2448 |
"dev": true,
|
| 2449 |
-
"libc": [
|
| 2450 |
-
"glibc"
|
| 2451 |
-
],
|
| 2452 |
"license": "MIT",
|
| 2453 |
"optional": true,
|
| 2454 |
"os": [
|
|
@@ -2466,9 +2392,6 @@
|
|
| 2466 |
"arm64"
|
| 2467 |
],
|
| 2468 |
"dev": true,
|
| 2469 |
-
"libc": [
|
| 2470 |
-
"musl"
|
| 2471 |
-
],
|
| 2472 |
"license": "MIT",
|
| 2473 |
"optional": true,
|
| 2474 |
"os": [
|
|
@@ -2486,9 +2409,6 @@
|
|
| 2486 |
"x64"
|
| 2487 |
],
|
| 2488 |
"dev": true,
|
| 2489 |
-
"libc": [
|
| 2490 |
-
"glibc"
|
| 2491 |
-
],
|
| 2492 |
"license": "MIT",
|
| 2493 |
"optional": true,
|
| 2494 |
"os": [
|
|
@@ -2506,9 +2426,6 @@
|
|
| 2506 |
"x64"
|
| 2507 |
],
|
| 2508 |
"dev": true,
|
| 2509 |
-
"libc": [
|
| 2510 |
-
"musl"
|
| 2511 |
-
],
|
| 2512 |
"license": "MIT",
|
| 2513 |
"optional": true,
|
| 2514 |
"os": [
|
|
@@ -2749,6 +2666,7 @@
|
|
| 2749 |
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.39.tgz",
|
| 2750 |
"integrity": "sha512-orrrD74MBUyK8jOAD/r0+lfa1I2MO6I+vAkmAWzMYbCcgrN4lCrmK52gRFQq/JRxfYPfonkr4b0jcY7Olqdqbw==",
|
| 2751 |
"license": "MIT",
|
|
|
|
| 2752 |
"dependencies": {
|
| 2753 |
"undici-types": "~6.21.0"
|
| 2754 |
}
|
|
@@ -2758,6 +2676,7 @@
|
|
| 2758 |
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
|
| 2759 |
"integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
|
| 2760 |
"license": "MIT",
|
|
|
|
| 2761 |
"dependencies": {
|
| 2762 |
"csstype": "^3.2.2"
|
| 2763 |
}
|
|
@@ -2844,6 +2763,7 @@
|
|
| 2844 |
"integrity": "sha512-TI1XGwKbDpo9tRW8UDIXCOeLk55qe9ZFGs8MTKU6/M08HWTw52DD/IYhfQtOEhEdPhLMT26Ka/x7p70nd3dzDg==",
|
| 2845 |
"dev": true,
|
| 2846 |
"license": "MIT",
|
|
|
|
| 2847 |
"dependencies": {
|
| 2848 |
"@typescript-eslint/scope-manager": "8.59.0",
|
| 2849 |
"@typescript-eslint/types": "8.59.0",
|
|
@@ -3206,9 +3126,6 @@
|
|
| 3206 |
"arm64"
|
| 3207 |
],
|
| 3208 |
"dev": true,
|
| 3209 |
-
"libc": [
|
| 3210 |
-
"glibc"
|
| 3211 |
-
],
|
| 3212 |
"license": "MIT",
|
| 3213 |
"optional": true,
|
| 3214 |
"os": [
|
|
@@ -3223,9 +3140,6 @@
|
|
| 3223 |
"arm64"
|
| 3224 |
],
|
| 3225 |
"dev": true,
|
| 3226 |
-
"libc": [
|
| 3227 |
-
"musl"
|
| 3228 |
-
],
|
| 3229 |
"license": "MIT",
|
| 3230 |
"optional": true,
|
| 3231 |
"os": [
|
|
@@ -3240,9 +3154,6 @@
|
|
| 3240 |
"ppc64"
|
| 3241 |
],
|
| 3242 |
"dev": true,
|
| 3243 |
-
"libc": [
|
| 3244 |
-
"glibc"
|
| 3245 |
-
],
|
| 3246 |
"license": "MIT",
|
| 3247 |
"optional": true,
|
| 3248 |
"os": [
|
|
@@ -3257,9 +3168,6 @@
|
|
| 3257 |
"riscv64"
|
| 3258 |
],
|
| 3259 |
"dev": true,
|
| 3260 |
-
"libc": [
|
| 3261 |
-
"glibc"
|
| 3262 |
-
],
|
| 3263 |
"license": "MIT",
|
| 3264 |
"optional": true,
|
| 3265 |
"os": [
|
|
@@ -3274,9 +3182,6 @@
|
|
| 3274 |
"riscv64"
|
| 3275 |
],
|
| 3276 |
"dev": true,
|
| 3277 |
-
"libc": [
|
| 3278 |
-
"musl"
|
| 3279 |
-
],
|
| 3280 |
"license": "MIT",
|
| 3281 |
"optional": true,
|
| 3282 |
"os": [
|
|
@@ -3291,9 +3196,6 @@
|
|
| 3291 |
"s390x"
|
| 3292 |
],
|
| 3293 |
"dev": true,
|
| 3294 |
-
"libc": [
|
| 3295 |
-
"glibc"
|
| 3296 |
-
],
|
| 3297 |
"license": "MIT",
|
| 3298 |
"optional": true,
|
| 3299 |
"os": [
|
|
@@ -3308,9 +3210,6 @@
|
|
| 3308 |
"x64"
|
| 3309 |
],
|
| 3310 |
"dev": true,
|
| 3311 |
-
"libc": [
|
| 3312 |
-
"glibc"
|
| 3313 |
-
],
|
| 3314 |
"license": "MIT",
|
| 3315 |
"optional": true,
|
| 3316 |
"os": [
|
|
@@ -3325,9 +3224,6 @@
|
|
| 3325 |
"x64"
|
| 3326 |
],
|
| 3327 |
"dev": true,
|
| 3328 |
-
"libc": [
|
| 3329 |
-
"musl"
|
| 3330 |
-
],
|
| 3331 |
"license": "MIT",
|
| 3332 |
"optional": true,
|
| 3333 |
"os": [
|
|
@@ -3412,6 +3308,7 @@
|
|
| 3412 |
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
|
| 3413 |
"dev": true,
|
| 3414 |
"license": "MIT",
|
|
|
|
| 3415 |
"bin": {
|
| 3416 |
"acorn": "bin/acorn"
|
| 3417 |
},
|
|
@@ -3866,6 +3763,7 @@
|
|
| 3866 |
}
|
| 3867 |
],
|
| 3868 |
"license": "MIT",
|
|
|
|
| 3869 |
"dependencies": {
|
| 3870 |
"baseline-browser-mapping": "^2.10.12",
|
| 3871 |
"caniuse-lite": "^1.0.30001782",
|
|
@@ -4917,6 +4815,7 @@
|
|
| 4917 |
"integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==",
|
| 4918 |
"dev": true,
|
| 4919 |
"license": "MIT",
|
|
|
|
| 4920 |
"dependencies": {
|
| 4921 |
"@eslint-community/eslint-utils": "^4.8.0",
|
| 4922 |
"@eslint-community/regexpp": "^4.12.1",
|
|
@@ -5102,6 +5001,7 @@
|
|
| 5102 |
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
| 5103 |
"dev": true,
|
| 5104 |
"license": "MIT",
|
|
|
|
| 5105 |
"dependencies": {
|
| 5106 |
"@rtsao/scc": "^1.1.0",
|
| 5107 |
"array-includes": "^3.1.9",
|
|
@@ -5401,6 +5301,7 @@
|
|
| 5401 |
"resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
|
| 5402 |
"integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
|
| 5403 |
"license": "MIT",
|
|
|
|
| 5404 |
"dependencies": {
|
| 5405 |
"accepts": "^2.0.0",
|
| 5406 |
"body-parser": "^2.2.1",
|
|
@@ -6172,6 +6073,7 @@
|
|
| 6172 |
"resolved": "https://registry.npmjs.org/hono/-/hono-4.12.14.tgz",
|
| 6173 |
"integrity": "sha512-am5zfg3yu6sqn5yjKBNqhnTX7Cv+m00ox+7jbaKkrLMRJ4rAdldd1xPd/JzbBWspqaQv6RSTrgFN95EsfhC+7w==",
|
| 6174 |
"license": "MIT",
|
|
|
|
| 6175 |
"engines": {
|
| 6176 |
"node": ">=16.9.0"
|
| 6177 |
}
|
|
@@ -7288,9 +7190,6 @@
|
|
| 7288 |
"arm64"
|
| 7289 |
],
|
| 7290 |
"dev": true,
|
| 7291 |
-
"libc": [
|
| 7292 |
-
"glibc"
|
| 7293 |
-
],
|
| 7294 |
"license": "MPL-2.0",
|
| 7295 |
"optional": true,
|
| 7296 |
"os": [
|
|
@@ -7312,9 +7211,6 @@
|
|
| 7312 |
"arm64"
|
| 7313 |
],
|
| 7314 |
"dev": true,
|
| 7315 |
-
"libc": [
|
| 7316 |
-
"musl"
|
| 7317 |
-
],
|
| 7318 |
"license": "MPL-2.0",
|
| 7319 |
"optional": true,
|
| 7320 |
"os": [
|
|
@@ -7336,9 +7232,6 @@
|
|
| 7336 |
"x64"
|
| 7337 |
],
|
| 7338 |
"dev": true,
|
| 7339 |
-
"libc": [
|
| 7340 |
-
"glibc"
|
| 7341 |
-
],
|
| 7342 |
"license": "MPL-2.0",
|
| 7343 |
"optional": true,
|
| 7344 |
"os": [
|
|
@@ -7360,9 +7253,6 @@
|
|
| 7360 |
"x64"
|
| 7361 |
],
|
| 7362 |
"dev": true,
|
| 7363 |
-
"libc": [
|
| 7364 |
-
"musl"
|
| 7365 |
-
],
|
| 7366 |
"license": "MPL-2.0",
|
| 7367 |
"optional": true,
|
| 7368 |
"os": [
|
|
@@ -9521,6 +9411,7 @@
|
|
| 9521 |
"resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
|
| 9522 |
"integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
|
| 9523 |
"license": "MIT",
|
|
|
|
| 9524 |
"engines": {
|
| 9525 |
"node": ">=0.10.0"
|
| 9526 |
}
|
|
@@ -9530,6 +9421,7 @@
|
|
| 9530 |
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
|
| 9531 |
"integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
|
| 9532 |
"license": "MIT",
|
|
|
|
| 9533 |
"dependencies": {
|
| 9534 |
"scheduler": "^0.27.0"
|
| 9535 |
},
|
|
@@ -10810,6 +10702,7 @@
|
|
| 10810 |
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
| 10811 |
"dev": true,
|
| 10812 |
"license": "MIT",
|
|
|
|
| 10813 |
"engines": {
|
| 10814 |
"node": ">=12"
|
| 10815 |
},
|
|
@@ -11078,6 +10971,7 @@
|
|
| 11078 |
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
| 11079 |
"devOptional": true,
|
| 11080 |
"license": "Apache-2.0",
|
|
|
|
| 11081 |
"bin": {
|
| 11082 |
"tsc": "bin/tsc",
|
| 11083 |
"tsserver": "bin/tsserver"
|
|
@@ -11737,6 +11631,7 @@
|
|
| 11737 |
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
|
| 11738 |
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
|
| 11739 |
"license": "MIT",
|
|
|
|
| 11740 |
"funding": {
|
| 11741 |
"url": "https://github.com/sponsors/colinhacks"
|
| 11742 |
}
|
|
@@ -11763,6 +11658,35 @@
|
|
| 11763 |
"zod": "^3.25.0 || ^4.0.0"
|
| 11764 |
}
|
| 11765 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11766 |
"node_modules/zwitch": {
|
| 11767 |
"version": "2.0.4",
|
| 11768 |
"resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz",
|
|
|
|
| 22 |
"remark-gfm": "^4.0.1",
|
| 23 |
"shadcn": "^4.3.1",
|
| 24 |
"tailwind-merge": "^3.5.0",
|
| 25 |
+
"tw-animate-css": "^1.4.0",
|
| 26 |
+
"zustand": "^5.0.13"
|
| 27 |
},
|
| 28 |
"devDependencies": {
|
| 29 |
"@tailwindcss/postcss": "^4",
|
|
|
|
| 77 |
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
|
| 78 |
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
| 79 |
"license": "MIT",
|
| 80 |
+
"peer": true,
|
| 81 |
"dependencies": {
|
| 82 |
"@babel/code-frame": "^7.29.0",
|
| 83 |
"@babel/generator": "^7.29.0",
|
|
|
|
| 671 |
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
| 672 |
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
| 673 |
"license": "MIT",
|
| 674 |
+
"peer": true,
|
| 675 |
"engines": {
|
| 676 |
"node": ">=12"
|
| 677 |
},
|
|
|
|
| 1109 |
"cpu": [
|
| 1110 |
"arm"
|
| 1111 |
],
|
|
|
|
|
|
|
|
|
|
| 1112 |
"license": "LGPL-3.0-or-later",
|
| 1113 |
"optional": true,
|
| 1114 |
"os": [
|
|
|
|
| 1125 |
"cpu": [
|
| 1126 |
"arm64"
|
| 1127 |
],
|
|
|
|
|
|
|
|
|
|
| 1128 |
"license": "LGPL-3.0-or-later",
|
| 1129 |
"optional": true,
|
| 1130 |
"os": [
|
|
|
|
| 1141 |
"cpu": [
|
| 1142 |
"ppc64"
|
| 1143 |
],
|
|
|
|
|
|
|
|
|
|
| 1144 |
"license": "LGPL-3.0-or-later",
|
| 1145 |
"optional": true,
|
| 1146 |
"os": [
|
|
|
|
| 1157 |
"cpu": [
|
| 1158 |
"riscv64"
|
| 1159 |
],
|
|
|
|
|
|
|
|
|
|
| 1160 |
"license": "LGPL-3.0-or-later",
|
| 1161 |
"optional": true,
|
| 1162 |
"os": [
|
|
|
|
| 1173 |
"cpu": [
|
| 1174 |
"s390x"
|
| 1175 |
],
|
|
|
|
|
|
|
|
|
|
| 1176 |
"license": "LGPL-3.0-or-later",
|
| 1177 |
"optional": true,
|
| 1178 |
"os": [
|
|
|
|
| 1189 |
"cpu": [
|
| 1190 |
"x64"
|
| 1191 |
],
|
|
|
|
|
|
|
|
|
|
| 1192 |
"license": "LGPL-3.0-or-later",
|
| 1193 |
"optional": true,
|
| 1194 |
"os": [
|
|
|
|
| 1205 |
"cpu": [
|
| 1206 |
"arm64"
|
| 1207 |
],
|
|
|
|
|
|
|
|
|
|
| 1208 |
"license": "LGPL-3.0-or-later",
|
| 1209 |
"optional": true,
|
| 1210 |
"os": [
|
|
|
|
| 1221 |
"cpu": [
|
| 1222 |
"x64"
|
| 1223 |
],
|
|
|
|
|
|
|
|
|
|
| 1224 |
"license": "LGPL-3.0-or-later",
|
| 1225 |
"optional": true,
|
| 1226 |
"os": [
|
|
|
|
| 1237 |
"cpu": [
|
| 1238 |
"arm"
|
| 1239 |
],
|
|
|
|
|
|
|
|
|
|
| 1240 |
"license": "Apache-2.0",
|
| 1241 |
"optional": true,
|
| 1242 |
"os": [
|
|
|
|
| 1259 |
"cpu": [
|
| 1260 |
"arm64"
|
| 1261 |
],
|
|
|
|
|
|
|
|
|
|
| 1262 |
"license": "Apache-2.0",
|
| 1263 |
"optional": true,
|
| 1264 |
"os": [
|
|
|
|
| 1281 |
"cpu": [
|
| 1282 |
"ppc64"
|
| 1283 |
],
|
|
|
|
|
|
|
|
|
|
| 1284 |
"license": "Apache-2.0",
|
| 1285 |
"optional": true,
|
| 1286 |
"os": [
|
|
|
|
| 1303 |
"cpu": [
|
| 1304 |
"riscv64"
|
| 1305 |
],
|
|
|
|
|
|
|
|
|
|
| 1306 |
"license": "Apache-2.0",
|
| 1307 |
"optional": true,
|
| 1308 |
"os": [
|
|
|
|
| 1325 |
"cpu": [
|
| 1326 |
"s390x"
|
| 1327 |
],
|
|
|
|
|
|
|
|
|
|
| 1328 |
"license": "Apache-2.0",
|
| 1329 |
"optional": true,
|
| 1330 |
"os": [
|
|
|
|
| 1347 |
"cpu": [
|
| 1348 |
"x64"
|
| 1349 |
],
|
|
|
|
|
|
|
|
|
|
| 1350 |
"license": "Apache-2.0",
|
| 1351 |
"optional": true,
|
| 1352 |
"os": [
|
|
|
|
| 1369 |
"cpu": [
|
| 1370 |
"arm64"
|
| 1371 |
],
|
|
|
|
|
|
|
|
|
|
| 1372 |
"license": "Apache-2.0",
|
| 1373 |
"optional": true,
|
| 1374 |
"os": [
|
|
|
|
| 1391 |
"cpu": [
|
| 1392 |
"x64"
|
| 1393 |
],
|
|
|
|
|
|
|
|
|
|
| 1394 |
"license": "Apache-2.0",
|
| 1395 |
"optional": true,
|
| 1396 |
"os": [
|
|
|
|
| 1811 |
"cpu": [
|
| 1812 |
"arm64"
|
| 1813 |
],
|
|
|
|
|
|
|
|
|
|
| 1814 |
"license": "MIT",
|
| 1815 |
"optional": true,
|
| 1816 |
"os": [
|
|
|
|
| 1831 |
"cpu": [
|
| 1832 |
"arm64"
|
| 1833 |
],
|
|
|
|
|
|
|
|
|
|
| 1834 |
"license": "MIT",
|
| 1835 |
"optional": true,
|
| 1836 |
"os": [
|
|
|
|
| 1851 |
"cpu": [
|
| 1852 |
"riscv64"
|
| 1853 |
],
|
|
|
|
|
|
|
|
|
|
| 1854 |
"license": "MIT",
|
| 1855 |
"optional": true,
|
| 1856 |
"os": [
|
|
|
|
| 1871 |
"cpu": [
|
| 1872 |
"x64"
|
| 1873 |
],
|
|
|
|
|
|
|
|
|
|
| 1874 |
"license": "MIT",
|
| 1875 |
"optional": true,
|
| 1876 |
"os": [
|
|
|
|
| 1891 |
"cpu": [
|
| 1892 |
"x64"
|
| 1893 |
],
|
|
|
|
|
|
|
|
|
|
| 1894 |
"license": "MIT",
|
| 1895 |
"optional": true,
|
| 1896 |
"os": [
|
|
|
|
| 2012 |
"cpu": [
|
| 2013 |
"arm64"
|
| 2014 |
],
|
|
|
|
|
|
|
|
|
|
| 2015 |
"license": "MIT",
|
| 2016 |
"optional": true,
|
| 2017 |
"os": [
|
|
|
|
| 2028 |
"cpu": [
|
| 2029 |
"arm64"
|
| 2030 |
],
|
|
|
|
|
|
|
|
|
|
| 2031 |
"license": "MIT",
|
| 2032 |
"optional": true,
|
| 2033 |
"os": [
|
|
|
|
| 2044 |
"cpu": [
|
| 2045 |
"x64"
|
| 2046 |
],
|
|
|
|
|
|
|
|
|
|
| 2047 |
"license": "MIT",
|
| 2048 |
"optional": true,
|
| 2049 |
"os": [
|
|
|
|
| 2060 |
"cpu": [
|
| 2061 |
"x64"
|
| 2062 |
],
|
|
|
|
|
|
|
|
|
|
| 2063 |
"license": "MIT",
|
| 2064 |
"optional": true,
|
| 2065 |
"os": [
|
|
|
|
| 2106 |
"resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz",
|
| 2107 |
"integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==",
|
| 2108 |
"license": "MIT",
|
| 2109 |
+
"peer": true,
|
| 2110 |
"engines": {
|
| 2111 |
"node": "^14.21.3 || >=16"
|
| 2112 |
},
|
|
|
|
| 2375 |
"arm64"
|
| 2376 |
],
|
| 2377 |
"dev": true,
|
|
|
|
|
|
|
|
|
|
| 2378 |
"license": "MIT",
|
| 2379 |
"optional": true,
|
| 2380 |
"os": [
|
|
|
|
| 2392 |
"arm64"
|
| 2393 |
],
|
| 2394 |
"dev": true,
|
|
|
|
|
|
|
|
|
|
| 2395 |
"license": "MIT",
|
| 2396 |
"optional": true,
|
| 2397 |
"os": [
|
|
|
|
| 2409 |
"x64"
|
| 2410 |
],
|
| 2411 |
"dev": true,
|
|
|
|
|
|
|
|
|
|
| 2412 |
"license": "MIT",
|
| 2413 |
"optional": true,
|
| 2414 |
"os": [
|
|
|
|
| 2426 |
"x64"
|
| 2427 |
],
|
| 2428 |
"dev": true,
|
|
|
|
|
|
|
|
|
|
| 2429 |
"license": "MIT",
|
| 2430 |
"optional": true,
|
| 2431 |
"os": [
|
|
|
|
| 2666 |
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.39.tgz",
|
| 2667 |
"integrity": "sha512-orrrD74MBUyK8jOAD/r0+lfa1I2MO6I+vAkmAWzMYbCcgrN4lCrmK52gRFQq/JRxfYPfonkr4b0jcY7Olqdqbw==",
|
| 2668 |
"license": "MIT",
|
| 2669 |
+
"peer": true,
|
| 2670 |
"dependencies": {
|
| 2671 |
"undici-types": "~6.21.0"
|
| 2672 |
}
|
|
|
|
| 2676 |
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
|
| 2677 |
"integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
|
| 2678 |
"license": "MIT",
|
| 2679 |
+
"peer": true,
|
| 2680 |
"dependencies": {
|
| 2681 |
"csstype": "^3.2.2"
|
| 2682 |
}
|
|
|
|
| 2763 |
"integrity": "sha512-TI1XGwKbDpo9tRW8UDIXCOeLk55qe9ZFGs8MTKU6/M08HWTw52DD/IYhfQtOEhEdPhLMT26Ka/x7p70nd3dzDg==",
|
| 2764 |
"dev": true,
|
| 2765 |
"license": "MIT",
|
| 2766 |
+
"peer": true,
|
| 2767 |
"dependencies": {
|
| 2768 |
"@typescript-eslint/scope-manager": "8.59.0",
|
| 2769 |
"@typescript-eslint/types": "8.59.0",
|
|
|
|
| 3126 |
"arm64"
|
| 3127 |
],
|
| 3128 |
"dev": true,
|
|
|
|
|
|
|
|
|
|
| 3129 |
"license": "MIT",
|
| 3130 |
"optional": true,
|
| 3131 |
"os": [
|
|
|
|
| 3140 |
"arm64"
|
| 3141 |
],
|
| 3142 |
"dev": true,
|
|
|
|
|
|
|
|
|
|
| 3143 |
"license": "MIT",
|
| 3144 |
"optional": true,
|
| 3145 |
"os": [
|
|
|
|
| 3154 |
"ppc64"
|
| 3155 |
],
|
| 3156 |
"dev": true,
|
|
|
|
|
|
|
|
|
|
| 3157 |
"license": "MIT",
|
| 3158 |
"optional": true,
|
| 3159 |
"os": [
|
|
|
|
| 3168 |
"riscv64"
|
| 3169 |
],
|
| 3170 |
"dev": true,
|
|
|
|
|
|
|
|
|
|
| 3171 |
"license": "MIT",
|
| 3172 |
"optional": true,
|
| 3173 |
"os": [
|
|
|
|
| 3182 |
"riscv64"
|
| 3183 |
],
|
| 3184 |
"dev": true,
|
|
|
|
|
|
|
|
|
|
| 3185 |
"license": "MIT",
|
| 3186 |
"optional": true,
|
| 3187 |
"os": [
|
|
|
|
| 3196 |
"s390x"
|
| 3197 |
],
|
| 3198 |
"dev": true,
|
|
|
|
|
|
|
|
|
|
| 3199 |
"license": "MIT",
|
| 3200 |
"optional": true,
|
| 3201 |
"os": [
|
|
|
|
| 3210 |
"x64"
|
| 3211 |
],
|
| 3212 |
"dev": true,
|
|
|
|
|
|
|
|
|
|
| 3213 |
"license": "MIT",
|
| 3214 |
"optional": true,
|
| 3215 |
"os": [
|
|
|
|
| 3224 |
"x64"
|
| 3225 |
],
|
| 3226 |
"dev": true,
|
|
|
|
|
|
|
|
|
|
| 3227 |
"license": "MIT",
|
| 3228 |
"optional": true,
|
| 3229 |
"os": [
|
|
|
|
| 3308 |
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
|
| 3309 |
"dev": true,
|
| 3310 |
"license": "MIT",
|
| 3311 |
+
"peer": true,
|
| 3312 |
"bin": {
|
| 3313 |
"acorn": "bin/acorn"
|
| 3314 |
},
|
|
|
|
| 3763 |
}
|
| 3764 |
],
|
| 3765 |
"license": "MIT",
|
| 3766 |
+
"peer": true,
|
| 3767 |
"dependencies": {
|
| 3768 |
"baseline-browser-mapping": "^2.10.12",
|
| 3769 |
"caniuse-lite": "^1.0.30001782",
|
|
|
|
| 4815 |
"integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==",
|
| 4816 |
"dev": true,
|
| 4817 |
"license": "MIT",
|
| 4818 |
+
"peer": true,
|
| 4819 |
"dependencies": {
|
| 4820 |
"@eslint-community/eslint-utils": "^4.8.0",
|
| 4821 |
"@eslint-community/regexpp": "^4.12.1",
|
|
|
|
| 5001 |
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
| 5002 |
"dev": true,
|
| 5003 |
"license": "MIT",
|
| 5004 |
+
"peer": true,
|
| 5005 |
"dependencies": {
|
| 5006 |
"@rtsao/scc": "^1.1.0",
|
| 5007 |
"array-includes": "^3.1.9",
|
|
|
|
| 5301 |
"resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
|
| 5302 |
"integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
|
| 5303 |
"license": "MIT",
|
| 5304 |
+
"peer": true,
|
| 5305 |
"dependencies": {
|
| 5306 |
"accepts": "^2.0.0",
|
| 5307 |
"body-parser": "^2.2.1",
|
|
|
|
| 6073 |
"resolved": "https://registry.npmjs.org/hono/-/hono-4.12.14.tgz",
|
| 6074 |
"integrity": "sha512-am5zfg3yu6sqn5yjKBNqhnTX7Cv+m00ox+7jbaKkrLMRJ4rAdldd1xPd/JzbBWspqaQv6RSTrgFN95EsfhC+7w==",
|
| 6075 |
"license": "MIT",
|
| 6076 |
+
"peer": true,
|
| 6077 |
"engines": {
|
| 6078 |
"node": ">=16.9.0"
|
| 6079 |
}
|
|
|
|
| 7190 |
"arm64"
|
| 7191 |
],
|
| 7192 |
"dev": true,
|
|
|
|
|
|
|
|
|
|
| 7193 |
"license": "MPL-2.0",
|
| 7194 |
"optional": true,
|
| 7195 |
"os": [
|
|
|
|
| 7211 |
"arm64"
|
| 7212 |
],
|
| 7213 |
"dev": true,
|
|
|
|
|
|
|
|
|
|
| 7214 |
"license": "MPL-2.0",
|
| 7215 |
"optional": true,
|
| 7216 |
"os": [
|
|
|
|
| 7232 |
"x64"
|
| 7233 |
],
|
| 7234 |
"dev": true,
|
|
|
|
|
|
|
|
|
|
| 7235 |
"license": "MPL-2.0",
|
| 7236 |
"optional": true,
|
| 7237 |
"os": [
|
|
|
|
| 7253 |
"x64"
|
| 7254 |
],
|
| 7255 |
"dev": true,
|
|
|
|
|
|
|
|
|
|
| 7256 |
"license": "MPL-2.0",
|
| 7257 |
"optional": true,
|
| 7258 |
"os": [
|
|
|
|
| 9411 |
"resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
|
| 9412 |
"integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
|
| 9413 |
"license": "MIT",
|
| 9414 |
+
"peer": true,
|
| 9415 |
"engines": {
|
| 9416 |
"node": ">=0.10.0"
|
| 9417 |
}
|
|
|
|
| 9421 |
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
|
| 9422 |
"integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
|
| 9423 |
"license": "MIT",
|
| 9424 |
+
"peer": true,
|
| 9425 |
"dependencies": {
|
| 9426 |
"scheduler": "^0.27.0"
|
| 9427 |
},
|
|
|
|
| 10702 |
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
| 10703 |
"dev": true,
|
| 10704 |
"license": "MIT",
|
| 10705 |
+
"peer": true,
|
| 10706 |
"engines": {
|
| 10707 |
"node": ">=12"
|
| 10708 |
},
|
|
|
|
| 10971 |
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
| 10972 |
"devOptional": true,
|
| 10973 |
"license": "Apache-2.0",
|
| 10974 |
+
"peer": true,
|
| 10975 |
"bin": {
|
| 10976 |
"tsc": "bin/tsc",
|
| 10977 |
"tsserver": "bin/tsserver"
|
|
|
|
| 11631 |
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
|
| 11632 |
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
|
| 11633 |
"license": "MIT",
|
| 11634 |
+
"peer": true,
|
| 11635 |
"funding": {
|
| 11636 |
"url": "https://github.com/sponsors/colinhacks"
|
| 11637 |
}
|
|
|
|
| 11658 |
"zod": "^3.25.0 || ^4.0.0"
|
| 11659 |
}
|
| 11660 |
},
|
| 11661 |
+
"node_modules/zustand": {
|
| 11662 |
+
"version": "5.0.13",
|
| 11663 |
+
"resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.13.tgz",
|
| 11664 |
+
"integrity": "sha512-efI2tVaVQPqtOh114loML/Z80Y4NP3yc+Ff0fYiZJPauNeWZeIp/bRFD7I9bfmCOYBh/PHxlglQ9+wvlwnPikQ==",
|
| 11665 |
+
"license": "MIT",
|
| 11666 |
+
"engines": {
|
| 11667 |
+
"node": ">=12.20.0"
|
| 11668 |
+
},
|
| 11669 |
+
"peerDependencies": {
|
| 11670 |
+
"@types/react": ">=18.0.0",
|
| 11671 |
+
"immer": ">=9.0.6",
|
| 11672 |
+
"react": ">=18.0.0",
|
| 11673 |
+
"use-sync-external-store": ">=1.2.0"
|
| 11674 |
+
},
|
| 11675 |
+
"peerDependenciesMeta": {
|
| 11676 |
+
"@types/react": {
|
| 11677 |
+
"optional": true
|
| 11678 |
+
},
|
| 11679 |
+
"immer": {
|
| 11680 |
+
"optional": true
|
| 11681 |
+
},
|
| 11682 |
+
"react": {
|
| 11683 |
+
"optional": true
|
| 11684 |
+
},
|
| 11685 |
+
"use-sync-external-store": {
|
| 11686 |
+
"optional": true
|
| 11687 |
+
}
|
| 11688 |
+
}
|
| 11689 |
+
},
|
| 11690 |
"node_modules/zwitch": {
|
| 11691 |
"version": "2.0.4",
|
| 11692 |
"resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz",
|
frontend/package.json
CHANGED
|
@@ -23,7 +23,8 @@
|
|
| 23 |
"remark-gfm": "^4.0.1",
|
| 24 |
"shadcn": "^4.3.1",
|
| 25 |
"tailwind-merge": "^3.5.0",
|
| 26 |
-
"tw-animate-css": "^1.4.0"
|
|
|
|
| 27 |
},
|
| 28 |
"devDependencies": {
|
| 29 |
"@tailwindcss/postcss": "^4",
|
|
|
|
| 23 |
"remark-gfm": "^4.0.1",
|
| 24 |
"shadcn": "^4.3.1",
|
| 25 |
"tailwind-merge": "^3.5.0",
|
| 26 |
+
"tw-animate-css": "^1.4.0",
|
| 27 |
+
"zustand": "^5.0.13"
|
| 28 |
},
|
| 29 |
"devDependencies": {
|
| 30 |
"@tailwindcss/postcss": "^4",
|
frontend/src/components/chat/ChatPanel.tsx
CHANGED
|
@@ -3,38 +3,28 @@
|
|
| 3 |
import { useState, useRef, useEffect } from "react";
|
| 4 |
import type { DocInfo } from "@/app/dashboard/page";
|
| 5 |
import { api, API_BASE } from "@/lib/api";
|
|
|
|
| 6 |
import { Button } from "@/components/ui/button";
|
| 7 |
import { Textarea } from "@/components/ui/textarea";
|
| 8 |
import MessageBubble from "./MessageBubble";
|
| 9 |
import SourceCard from "./SourceCard";
|
| 10 |
import { Send, Loader2, Trash2, MessageSquare, Download } from "lucide-react";
|
| 11 |
|
| 12 |
-
export interface SourceChunk {
|
| 13 |
-
text: string;
|
| 14 |
-
filename: string;
|
| 15 |
-
page: number;
|
| 16 |
-
score: number;
|
| 17 |
-
confidence: number;
|
| 18 |
-
}
|
| 19 |
-
|
| 20 |
-
export interface ChatMsg {
|
| 21 |
-
id: string;
|
| 22 |
-
role: "user" | "assistant";
|
| 23 |
-
content: string;
|
| 24 |
-
sources: SourceChunk[];
|
| 25 |
-
isStreaming?: boolean;
|
| 26 |
-
}
|
| 27 |
-
|
| 28 |
interface Props {
|
| 29 |
activeDoc: DocInfo | null;
|
| 30 |
onCitationClick: (page: number) => void;
|
| 31 |
}
|
| 32 |
|
| 33 |
export default function ChatPanel({ activeDoc, onCitationClick }: Props) {
|
| 34 |
-
const
|
| 35 |
-
const
|
| 36 |
-
const
|
| 37 |
-
const
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
const [showExportMenu, setShowExportMenu] = useState(false);
|
| 39 |
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
| 40 |
const bottomRef = useRef<HTMLDivElement>(null);
|
|
@@ -63,6 +53,12 @@ export default function ChatPanel({ activeDoc, onCitationClick }: Props) {
|
|
| 63 |
bottomRef.current?.scrollIntoView({ behavior: "smooth" });
|
| 64 |
}, [messages]);
|
| 65 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
// Load history on doc change
|
| 67 |
useEffect(() => {
|
| 68 |
if (!activeDoc) {
|
|
@@ -102,7 +98,7 @@ export default function ChatPanel({ activeDoc, onCitationClick }: Props) {
|
|
| 102 |
return () => {
|
| 103 |
cancelled = true;
|
| 104 |
};
|
| 105 |
-
}, [activeDoc]);
|
| 106 |
|
| 107 |
const handleSend = async () => {
|
| 108 |
if (!input.trim() || streaming) return;
|
|
@@ -369,4 +365,4 @@ export default function ChatPanel({ activeDoc, onCitationClick }: Props) {
|
|
| 369 |
</div>
|
| 370 |
</div>
|
| 371 |
);
|
| 372 |
-
}
|
|
|
|
| 3 |
import { useState, useRef, useEffect } from "react";
|
| 4 |
import type { DocInfo } from "@/app/dashboard/page";
|
| 5 |
import { api, API_BASE } from "@/lib/api";
|
| 6 |
+
import { useChatStore, type ChatMsg, type SourceChunk } from "@/store/chat-store";
|
| 7 |
import { Button } from "@/components/ui/button";
|
| 8 |
import { Textarea } from "@/components/ui/textarea";
|
| 9 |
import MessageBubble from "./MessageBubble";
|
| 10 |
import SourceCard from "./SourceCard";
|
| 11 |
import { Send, Loader2, Trash2, MessageSquare, Download } from "lucide-react";
|
| 12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
interface Props {
|
| 14 |
activeDoc: DocInfo | null;
|
| 15 |
onCitationClick: (page: number) => void;
|
| 16 |
}
|
| 17 |
|
| 18 |
export default function ChatPanel({ activeDoc, onCitationClick }: Props) {
|
| 19 |
+
const messages = useChatStore((state) => state.messages);
|
| 20 |
+
const input = useChatStore((state) => state.input);
|
| 21 |
+
const streaming = useChatStore((state) => state.streaming);
|
| 22 |
+
const isTyping = useChatStore((state) => state.isTyping);
|
| 23 |
+
const setMessages = useChatStore((state) => state.setMessages);
|
| 24 |
+
const setInput = useChatStore((state) => state.setInput);
|
| 25 |
+
const setStreaming = useChatStore((state) => state.setStreaming);
|
| 26 |
+
const setIsTyping = useChatStore((state) => state.setIsTyping);
|
| 27 |
+
const resetChat = useChatStore((state) => state.resetChat);
|
| 28 |
const [showExportMenu, setShowExportMenu] = useState(false);
|
| 29 |
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
| 30 |
const bottomRef = useRef<HTMLDivElement>(null);
|
|
|
|
| 53 |
bottomRef.current?.scrollIntoView({ behavior: "smooth" });
|
| 54 |
}, [messages]);
|
| 55 |
|
| 56 |
+
useEffect(() => {
|
| 57 |
+
return () => {
|
| 58 |
+
resetChat();
|
| 59 |
+
};
|
| 60 |
+
}, [resetChat]);
|
| 61 |
+
|
| 62 |
// Load history on doc change
|
| 63 |
useEffect(() => {
|
| 64 |
if (!activeDoc) {
|
|
|
|
| 98 |
return () => {
|
| 99 |
cancelled = true;
|
| 100 |
};
|
| 101 |
+
}, [activeDoc, resetChat, setMessages]);
|
| 102 |
|
| 103 |
const handleSend = async () => {
|
| 104 |
if (!input.trim() || streaming) return;
|
|
|
|
| 365 |
</div>
|
| 366 |
</div>
|
| 367 |
);
|
| 368 |
+
}
|
frontend/src/components/chat/MessageBubble.tsx
CHANGED
|
@@ -3,7 +3,7 @@
|
|
| 3 |
import { useState, useRef } from "react";
|
| 4 |
import ReactMarkdown from "react-markdown";
|
| 5 |
import remarkGfm from "remark-gfm";
|
| 6 |
-
import type { ChatMsg } from "
|
| 7 |
import { Brain, User, Copy, Check } from "lucide-react";
|
| 8 |
import { Button } from "@/components/ui/button";
|
| 9 |
|
|
|
|
| 3 |
import { useState, useRef } from "react";
|
| 4 |
import ReactMarkdown from "react-markdown";
|
| 5 |
import remarkGfm from "remark-gfm";
|
| 6 |
+
import type { ChatMsg } from "@/store/chat-store";
|
| 7 |
import { Brain, User, Copy, Check } from "lucide-react";
|
| 8 |
import { Button } from "@/components/ui/button";
|
| 9 |
|
frontend/src/components/chat/SourceCard.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
"use client";
|
| 2 |
|
| 3 |
import { useState } from "react";
|
| 4 |
-
import type { SourceChunk } from "
|
| 5 |
import { Badge } from "@/components/ui/badge";
|
| 6 |
import { Button } from "@/components/ui/button";
|
| 7 |
import { ChevronDown, ChevronUp, FileText, Eye } from "lucide-react";
|
|
|
|
| 1 |
"use client";
|
| 2 |
|
| 3 |
import { useState } from "react";
|
| 4 |
+
import type { SourceChunk } from "@/store/chat-store";
|
| 5 |
import { Badge } from "@/components/ui/badge";
|
| 6 |
import { Button } from "@/components/ui/button";
|
| 7 |
import { ChevronDown, ChevronUp, FileText, Eye } from "lucide-react";
|
frontend/src/lib/auth.tsx
CHANGED
|
@@ -1,73 +1,24 @@
|
|
| 1 |
"use client";
|
| 2 |
|
| 3 |
-
import React, {
|
| 4 |
-
import {
|
| 5 |
-
|
| 6 |
-
interface User {
|
| 7 |
-
id: string;
|
| 8 |
-
username: string;
|
| 9 |
-
email: string;
|
| 10 |
-
is_admin: boolean;
|
| 11 |
-
created_at: string;
|
| 12 |
-
}
|
| 13 |
-
|
| 14 |
-
interface AuthContextType {
|
| 15 |
-
user: User | null;
|
| 16 |
-
token: string | null;
|
| 17 |
-
loading: boolean;
|
| 18 |
-
login: (email: string, password: string) => Promise<void>;
|
| 19 |
-
register: (username: string, email: string, password: string) => Promise<void>;
|
| 20 |
-
logout: () => void;
|
| 21 |
-
}
|
| 22 |
-
|
| 23 |
-
const AuthContext = createContext<AuthContextType | undefined>(undefined);
|
| 24 |
|
| 25 |
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
| 26 |
-
const
|
| 27 |
-
|
| 28 |
-
const
|
| 29 |
-
() => (typeof window !== "undefined" ? localStorage.getItem("token") : null)
|
| 30 |
-
);
|
| 31 |
-
// loading=true only when a token exists and needs server validation.
|
| 32 |
-
// If there's no token we're already done — no effect setState needed.
|
| 33 |
-
const [loading, setLoading] = useState<boolean>(
|
| 34 |
-
() => typeof window !== "undefined" && !!localStorage.getItem("token")
|
| 35 |
-
);
|
| 36 |
|
| 37 |
-
// ── Validate saved token on mount ─────────────────
|
| 38 |
-
// NOTE: no synchronous setState here — setLoading/setUser/setToken are
|
| 39 |
-
// only called inside async callbacks (.then / .catch / .finally).
|
| 40 |
useEffect(() => {
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
.get<User>("/api/v1/auth/me", { token })
|
| 44 |
-
.then(setUser)
|
| 45 |
-
.catch(() => {
|
| 46 |
-
localStorage.removeItem("token");
|
| 47 |
-
localStorage.removeItem("refresh_token");
|
| 48 |
-
setToken(null);
|
| 49 |
-
})
|
| 50 |
-
.finally(() => setLoading(false));
|
| 51 |
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
| 52 |
-
}, []); // intentionally runs once on mount only
|
| 53 |
|
| 54 |
-
// ── Listen for token refresh events from ApiClient ──
|
| 55 |
-
// When the API client auto-refreshes tokens, it dispatches custom events
|
| 56 |
-
// so this context stays in sync without prop drilling.
|
| 57 |
useEffect(() => {
|
| 58 |
const handleTokensRefreshed = (e: Event) => {
|
| 59 |
-
|
| 60 |
-
if (detail?.accessToken) {
|
| 61 |
-
setToken(detail.accessToken);
|
| 62 |
-
}
|
| 63 |
-
if (detail?.user) {
|
| 64 |
-
setUser(detail.user);
|
| 65 |
-
}
|
| 66 |
};
|
| 67 |
|
| 68 |
const handleLoggedOut = () => {
|
| 69 |
-
|
| 70 |
-
setUser(null);
|
| 71 |
};
|
| 72 |
|
| 73 |
window.addEventListener("auth:tokens-refreshed", handleTokensRefreshed);
|
|
@@ -77,46 +28,11 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|
| 77 |
window.removeEventListener("auth:tokens-refreshed", handleTokensRefreshed);
|
| 78 |
window.removeEventListener("auth:logged-out", handleLoggedOut);
|
| 79 |
};
|
| 80 |
-
}, []);
|
| 81 |
-
|
| 82 |
-
const login = useCallback(async (email: string, password: string) => {
|
| 83 |
-
const data = await api.post<{ access_token: string; refresh_token: string; user: User }>(
|
| 84 |
-
"/api/v1/auth/login",
|
| 85 |
-
{ email, password }
|
| 86 |
-
);
|
| 87 |
-
localStorage.setItem("token", data.access_token);
|
| 88 |
-
localStorage.setItem("refresh_token", data.refresh_token);
|
| 89 |
-
setToken(data.access_token);
|
| 90 |
-
setUser(data.user);
|
| 91 |
-
}, []);
|
| 92 |
-
|
| 93 |
-
const register = useCallback(async (username: string, email: string, password: string) => {
|
| 94 |
-
const data = await api.post<{ access_token: string; refresh_token: string; user: User }>(
|
| 95 |
-
"/api/v1/auth/register",
|
| 96 |
-
{ username, email, password }
|
| 97 |
-
);
|
| 98 |
-
localStorage.setItem("token", data.access_token);
|
| 99 |
-
localStorage.setItem("refresh_token", data.refresh_token);
|
| 100 |
-
setToken(data.access_token);
|
| 101 |
-
setUser(data.user);
|
| 102 |
-
}, []);
|
| 103 |
-
|
| 104 |
-
const logout = useCallback(() => {
|
| 105 |
-
localStorage.removeItem("token");
|
| 106 |
-
localStorage.removeItem("refresh_token");
|
| 107 |
-
setToken(null);
|
| 108 |
-
setUser(null);
|
| 109 |
-
}, []);
|
| 110 |
|
| 111 |
-
return
|
| 112 |
-
<AuthContext.Provider value={{ user, token, loading, login, register, logout }}>
|
| 113 |
-
{children}
|
| 114 |
-
</AuthContext.Provider>
|
| 115 |
-
);
|
| 116 |
}
|
| 117 |
|
| 118 |
export function useAuth() {
|
| 119 |
-
|
| 120 |
-
if (!ctx) throw new Error("useAuth must be used within AuthProvider");
|
| 121 |
-
return ctx;
|
| 122 |
}
|
|
|
|
| 1 |
"use client";
|
| 2 |
|
| 3 |
+
import React, { useEffect } from "react";
|
| 4 |
+
import { useAuthStore } from "@/store/auth-store";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
| 7 |
+
const initializeAuth = useAuthStore((state) => state.initializeAuth);
|
| 8 |
+
const syncTokensRefreshed = useAuthStore((state) => state.syncTokensRefreshed);
|
| 9 |
+
const syncLoggedOut = useAuthStore((state) => state.syncLoggedOut);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
|
|
|
|
|
|
|
|
|
| 11 |
useEffect(() => {
|
| 12 |
+
void initializeAuth();
|
| 13 |
+
}, [initializeAuth]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
|
|
|
|
|
|
|
|
|
|
| 15 |
useEffect(() => {
|
| 16 |
const handleTokensRefreshed = (e: Event) => {
|
| 17 |
+
syncTokensRefreshed((e as CustomEvent).detail);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
};
|
| 19 |
|
| 20 |
const handleLoggedOut = () => {
|
| 21 |
+
syncLoggedOut();
|
|
|
|
| 22 |
};
|
| 23 |
|
| 24 |
window.addEventListener("auth:tokens-refreshed", handleTokensRefreshed);
|
|
|
|
| 28 |
window.removeEventListener("auth:tokens-refreshed", handleTokensRefreshed);
|
| 29 |
window.removeEventListener("auth:logged-out", handleLoggedOut);
|
| 30 |
};
|
| 31 |
+
}, [syncLoggedOut, syncTokensRefreshed]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
|
| 33 |
+
return <>{children}</>;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
}
|
| 35 |
|
| 36 |
export function useAuth() {
|
| 37 |
+
return useAuthStore();
|
|
|
|
|
|
|
| 38 |
}
|
frontend/src/store/auth-store.ts
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use client";
|
| 2 |
+
|
| 3 |
+
import { create } from "zustand";
|
| 4 |
+
import { api } from "@/lib/api";
|
| 5 |
+
|
| 6 |
+
export interface AuthUser {
|
| 7 |
+
id: string;
|
| 8 |
+
username: string;
|
| 9 |
+
email: string;
|
| 10 |
+
is_admin: boolean;
|
| 11 |
+
created_at: string;
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
interface AuthStore {
|
| 15 |
+
user: AuthUser | null;
|
| 16 |
+
token: string | null;
|
| 17 |
+
loading: boolean;
|
| 18 |
+
initialized: boolean;
|
| 19 |
+
login: (email: string, password: string) => Promise<void>;
|
| 20 |
+
register: (username: string, email: string, password: string) => Promise<void>;
|
| 21 |
+
logout: () => void;
|
| 22 |
+
initializeAuth: () => Promise<void>;
|
| 23 |
+
syncTokensRefreshed: (detail?: { accessToken?: string; user?: AuthUser | null }) => void;
|
| 24 |
+
syncLoggedOut: () => void;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
const getStoredToken = () =>
|
| 28 |
+
typeof window !== "undefined" ? localStorage.getItem("token") : null;
|
| 29 |
+
|
| 30 |
+
const clearStoredTokens = () => {
|
| 31 |
+
if (typeof window === "undefined") return;
|
| 32 |
+
localStorage.removeItem("token");
|
| 33 |
+
localStorage.removeItem("refresh_token");
|
| 34 |
+
};
|
| 35 |
+
|
| 36 |
+
export const useAuthStore = create<AuthStore>((set, get) => ({
|
| 37 |
+
user: null,
|
| 38 |
+
token: getStoredToken(),
|
| 39 |
+
loading: !!getStoredToken(),
|
| 40 |
+
initialized: false,
|
| 41 |
+
|
| 42 |
+
async login(email, password) {
|
| 43 |
+
const data = await api.post<{ access_token: string; refresh_token: string; user: AuthUser }>(
|
| 44 |
+
"/api/v1/auth/login",
|
| 45 |
+
{ email, password }
|
| 46 |
+
);
|
| 47 |
+
|
| 48 |
+
localStorage.setItem("token", data.access_token);
|
| 49 |
+
localStorage.setItem("refresh_token", data.refresh_token);
|
| 50 |
+
set({
|
| 51 |
+
token: data.access_token,
|
| 52 |
+
user: data.user,
|
| 53 |
+
loading: false,
|
| 54 |
+
initialized: true,
|
| 55 |
+
});
|
| 56 |
+
},
|
| 57 |
+
|
| 58 |
+
async register(username, email, password) {
|
| 59 |
+
const data = await api.post<{ access_token: string; refresh_token: string; user: AuthUser }>(
|
| 60 |
+
"/api/v1/auth/register",
|
| 61 |
+
{ username, email, password }
|
| 62 |
+
);
|
| 63 |
+
|
| 64 |
+
localStorage.setItem("token", data.access_token);
|
| 65 |
+
localStorage.setItem("refresh_token", data.refresh_token);
|
| 66 |
+
set({
|
| 67 |
+
token: data.access_token,
|
| 68 |
+
user: data.user,
|
| 69 |
+
loading: false,
|
| 70 |
+
initialized: true,
|
| 71 |
+
});
|
| 72 |
+
},
|
| 73 |
+
|
| 74 |
+
logout() {
|
| 75 |
+
clearStoredTokens();
|
| 76 |
+
set({
|
| 77 |
+
token: null,
|
| 78 |
+
user: null,
|
| 79 |
+
loading: false,
|
| 80 |
+
initialized: true,
|
| 81 |
+
});
|
| 82 |
+
},
|
| 83 |
+
|
| 84 |
+
async initializeAuth() {
|
| 85 |
+
const { initialized, token } = get();
|
| 86 |
+
if (initialized) return;
|
| 87 |
+
|
| 88 |
+
const storedToken = token ?? getStoredToken();
|
| 89 |
+
if (!storedToken) {
|
| 90 |
+
set({ token: null, user: null, loading: false, initialized: true });
|
| 91 |
+
return;
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
set({ token: storedToken, loading: true });
|
| 95 |
+
|
| 96 |
+
try {
|
| 97 |
+
const user = await api.get<AuthUser>("/api/v1/auth/me", { token: storedToken });
|
| 98 |
+
set({ user, token: storedToken, loading: false, initialized: true });
|
| 99 |
+
} catch {
|
| 100 |
+
clearStoredTokens();
|
| 101 |
+
set({ user: null, token: null, loading: false, initialized: true });
|
| 102 |
+
}
|
| 103 |
+
},
|
| 104 |
+
|
| 105 |
+
syncTokensRefreshed(detail) {
|
| 106 |
+
if (!detail) return;
|
| 107 |
+
|
| 108 |
+
set((state) => ({
|
| 109 |
+
token: detail.accessToken ?? state.token,
|
| 110 |
+
user: detail.user ?? state.user,
|
| 111 |
+
loading: false,
|
| 112 |
+
initialized: true,
|
| 113 |
+
}));
|
| 114 |
+
},
|
| 115 |
+
|
| 116 |
+
syncLoggedOut() {
|
| 117 |
+
set({
|
| 118 |
+
token: null,
|
| 119 |
+
user: null,
|
| 120 |
+
loading: false,
|
| 121 |
+
initialized: true,
|
| 122 |
+
});
|
| 123 |
+
},
|
| 124 |
+
}));
|
frontend/src/store/chat-store.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use client";
|
| 2 |
+
|
| 3 |
+
import { create } from "zustand";
|
| 4 |
+
|
| 5 |
+
export interface SourceChunk {
|
| 6 |
+
text: string;
|
| 7 |
+
filename: string;
|
| 8 |
+
page: number;
|
| 9 |
+
score: number;
|
| 10 |
+
confidence: number;
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
export interface ChatMsg {
|
| 14 |
+
id: string;
|
| 15 |
+
role: "user" | "assistant";
|
| 16 |
+
content: string;
|
| 17 |
+
sources: SourceChunk[];
|
| 18 |
+
isStreaming?: boolean;
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
type Setter<T> = T | ((prev: T) => T);
|
| 22 |
+
|
| 23 |
+
interface ChatStore {
|
| 24 |
+
messages: ChatMsg[];
|
| 25 |
+
input: string;
|
| 26 |
+
streaming: boolean;
|
| 27 |
+
isTyping: boolean;
|
| 28 |
+
setMessages: (value: Setter<ChatMsg[]>) => void;
|
| 29 |
+
setInput: (value: Setter<string>) => void;
|
| 30 |
+
setStreaming: (value: Setter<boolean>) => void;
|
| 31 |
+
setIsTyping: (value: Setter<boolean>) => void;
|
| 32 |
+
resetChat: () => void;
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
const resolveValue = <T,>(value: Setter<T>, current: T): T =>
|
| 36 |
+
typeof value === "function" ? (value as (prev: T) => T)(current) : value;
|
| 37 |
+
|
| 38 |
+
export const useChatStore = create<ChatStore>((set) => ({
|
| 39 |
+
messages: [],
|
| 40 |
+
input: "",
|
| 41 |
+
streaming: false,
|
| 42 |
+
isTyping: false,
|
| 43 |
+
|
| 44 |
+
setMessages(value) {
|
| 45 |
+
set((state) => ({ messages: resolveValue(value, state.messages) }));
|
| 46 |
+
},
|
| 47 |
+
|
| 48 |
+
setInput(value) {
|
| 49 |
+
set((state) => ({ input: resolveValue(value, state.input) }));
|
| 50 |
+
},
|
| 51 |
+
|
| 52 |
+
setStreaming(value) {
|
| 53 |
+
set((state) => ({ streaming: resolveValue(value, state.streaming) }));
|
| 54 |
+
},
|
| 55 |
+
|
| 56 |
+
setIsTyping(value) {
|
| 57 |
+
set((state) => ({ isTyping: resolveValue(value, state.isTyping) }));
|
| 58 |
+
},
|
| 59 |
+
|
| 60 |
+
resetChat() {
|
| 61 |
+
set({
|
| 62 |
+
messages: [],
|
| 63 |
+
input: "",
|
| 64 |
+
streaming: false,
|
| 65 |
+
isTyping: false,
|
| 66 |
+
});
|
| 67 |
+
},
|
| 68 |
+
}));
|