diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d5ba52a..3bce3e1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,7 +14,7 @@ importers: devDependencies: '@biomejs/biome': specifier: latest - version: 2.4.16 + version: 2.5.0 drizzle-kit: specifier: ^0.31.10 version: 0.31.10 @@ -91,7 +91,7 @@ importers: devDependencies: '@biomejs/biome': specifier: latest - version: 2.4.16 + version: 2.5.0 '@types/express': specifier: ^5.0.6 version: 5.0.6 @@ -112,7 +112,7 @@ importers: version: 5.9.3 vitest: specifier: latest - version: 4.1.8(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(vite@8.0.13(@types/node@25.9.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0)) + version: 4.1.9(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(vite@8.0.13(@types/node@25.9.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0)) services/discord-gateway: dependencies: @@ -194,7 +194,7 @@ importers: devDependencies: '@biomejs/biome': specifier: latest - version: 2.4.16 + version: 2.5.0 '@types/node': specifier: ^25.9.0 version: 25.9.0 @@ -215,7 +215,7 @@ importers: version: 5.9.3 vitest: specifier: latest - version: 4.1.8(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(vite@8.0.13(@types/node@25.9.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0)) + version: 4.1.9(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(vite@8.0.13(@types/node@25.9.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0)) services/frontend: dependencies: @@ -231,24 +231,12 @@ importers: '@radix-ui/react-tabs': specifier: ^1.1.13 version: 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@react-three/drei': - specifier: ^9.6.1 - version: 9.122.0(@react-three/fiber@9.6.1(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(three@0.174.0))(@types/react@19.2.14)(@types/three@0.184.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(three@0.174.0)(use-sync-external-store@1.6.0(react@19.2.6)) - '@react-three/fiber': - specifier: ^9.6.1 - version: 9.6.1(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(three@0.174.0) - '@tanstack/react-query': - specifier: ^5.100.14 - version: 5.100.14(react@19.2.6) clsx: specifier: ^2.1.1 version: 2.1.1 framer-motion: specifier: ^12.4.0 version: 12.40.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - gsap: - specifier: ^3.12.7 - version: 3.15.0 lucide-react: specifier: ^1.16.0 version: 1.16.0(react@19.2.6) @@ -261,13 +249,10 @@ importers: tailwind-merge: specifier: ^3.6.0 version: 3.6.0 - three: - specifier: ^0.174.0 - version: 0.174.0 devDependencies: '@biomejs/biome': specifier: latest - version: 2.4.16 + version: 2.5.0 '@tailwindcss/postcss': specifier: ^4.3.0 version: 4.3.0 @@ -277,9 +262,6 @@ importers: '@types/react-dom': specifier: ^19.2.3 version: 19.2.3(@types/react@19.2.14) - '@types/three': - specifier: ^0.184.1 - version: 0.184.1 '@vitejs/plugin-react': specifier: ^6.0.2 version: 6.0.2(vite@8.0.13(@types/node@25.9.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0)) @@ -395,7 +377,7 @@ importers: devDependencies: '@biomejs/biome': specifier: latest - version: 2.4.16 + version: 2.5.0 '@discordjs/docgen': specifier: ^0.11.1 version: 0.11.1 @@ -466,8 +448,8 @@ packages: engines: {node: '>=14.21.3'} hasBin: true - '@biomejs/biome@2.4.16': - resolution: {integrity: sha512-x9ajFh1zChVybCiM3TN6OD4phAqLgtPZjFrZF+aTMYCPjwBO+k529TX7PPsAqtGNLeV4UgzwQnowEgS7bGmzcA==} + '@biomejs/biome@2.5.0': + resolution: {integrity: sha512-4kURkd9hAPrdDM3C9n82ycYgx8hvQcW6MjKTEejruj8rK0N8P3OPpdy8BvI8kt3KWY4ycF5XtDOrktetEfhfuw==} engines: {node: '>=14.21.3'} hasBin: true @@ -477,8 +459,8 @@ packages: cpu: [arm64] os: [darwin] - '@biomejs/cli-darwin-arm64@2.4.16': - resolution: {integrity: sha512-wxPvu4XOA85YJk9ixSWUmq/QBHbid85BISbOAqqBM/5xQpPk9ayjk5375tOlSC0BeCwNSbPFafQBm+vBumXq0A==} + '@biomejs/cli-darwin-arm64@2.5.0': + resolution: {integrity: sha512-Mn3Fwi3SA5fgmfCPqmzpWF2DLZnms3BVAhM088nTnGrTZmHS3wwIjcoZPqpXeNgd3DrrLH6xp8vTLIBuJoZiXw==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [darwin] @@ -489,8 +471,8 @@ packages: cpu: [x64] os: [darwin] - '@biomejs/cli-darwin-x64@2.4.16': - resolution: {integrity: sha512-xFCqGPwYusQJp4N4NJLi1XJiZqjwFdjhT+KqtNy+Ug3qgfczqnTa6MSDvxJF6TkuDLoYJItMapz6tAf7kCekFw==} + '@biomejs/cli-darwin-x64@2.5.0': + resolution: {integrity: sha512-rg3VPL5P8mYro6pqlXYXuJWph21slVp3SZtAqWSrkZs40d2gTzYmHF8E/X1iTID25btmNKltNDJ926sqVBp7DQ==} engines: {node: '>=14.21.3'} cpu: [x64] os: [darwin] @@ -502,8 +484,8 @@ packages: os: [linux] libc: [musl] - '@biomejs/cli-linux-arm64-musl@2.4.16': - resolution: {integrity: sha512-oYxnW0ARfJkr72ezzF2OR8N/rtkgLUQeYtF8cFhVswbknHxtTcmzSsanVJP8yQKnGpGpc2ck6c5zLvHahL6Cbg==} + '@biomejs/cli-linux-arm64-musl@2.5.0': + resolution: {integrity: sha512-vQdM4oSGaf7ZNeGO9w5+Y8SBtyser9M6znxYbm7Ec8wInxJu1WiKxFYZW5Auj2d80bcVvefuGGRxoFOE0eee8g==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] @@ -516,8 +498,8 @@ packages: os: [linux] libc: [glibc] - '@biomejs/cli-linux-arm64@2.4.16': - resolution: {integrity: sha512-2kFb4//jxfZaP6D+Rj5VkHkxgyD9EoRAVBEQb8PKRv+s4NO2zYNJKXFaJmK1CmhufJOWEfpHKaRbOja7qjmdhQ==} + '@biomejs/cli-linux-arm64@2.5.0': + resolution: {integrity: sha512-tl+LW8fdD96/xdeWtWwc82LIOc5CoY7N2AsogLTp5R4ECErYt+8Jl/N68ezN9vzSiqPTxw6vjcihoLPYKZHrlw==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] @@ -530,8 +512,8 @@ packages: os: [linux] libc: [musl] - '@biomejs/cli-linux-x64-musl@2.4.16': - resolution: {integrity: sha512-iHDS+MCM65DPqWGu+ECC3uoALyj2H7F4nVUPxIPjz/PIl94EUu+EDfGZDzFP+NY1EOPVt9NQvwFqq7HdMmowdg==} + '@biomejs/cli-linux-x64-musl@2.5.0': + resolution: {integrity: sha512-+9hIcMngJ+yGUahXqZuZ8CoWKJE9SAZsFsM3QDvXpNsLbXZ9lqVzgBhOk/jTSYkOA0GLP9eu3teukqpLUojHMg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] @@ -544,8 +526,8 @@ packages: os: [linux] libc: [glibc] - '@biomejs/cli-linux-x64@2.4.16': - resolution: {integrity: sha512-NbcBbi/nJqn5baae6wqRXdS7Gadf2uRpehSh6vMSYpG8OhkXl/Xg8aorWrJ+9VWqAT5ml90alLvorkpMW0nBwQ==} + '@biomejs/cli-linux-x64@2.5.0': + resolution: {integrity: sha512-zpEGf4RQbFEh8Vt7OmavLyyOzRbtcE9osCqrS1kfvt8jDvxwhKXLSf7n0ebr/ov0RJ9ssP+lhs6C8a9WwFvrQA==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] @@ -557,8 +539,8 @@ packages: cpu: [arm64] os: [win32] - '@biomejs/cli-win32-arm64@2.4.16': - resolution: {integrity: sha512-0rgImMsNb5v/chhkIFe3wu7PEFClS6RBAYUijGL9UsYN3PanSaoK24HSSuSJb1pYbYYVjzAyZTl3gtjJ84BM8A==} + '@biomejs/cli-win32-arm64@2.5.0': + resolution: {integrity: sha512-jB0wAvTLI4itx5VidqVUejPQFhRUxiZ9l9FvZ26D5fl6t3qme+ZB4PD3bTSeL1vZ8NI2Rx/zj6H9zcESuGHKGw==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [win32] @@ -569,8 +551,8 @@ packages: cpu: [x64] os: [win32] - '@biomejs/cli-win32-x64@2.4.16': - resolution: {integrity: sha512-Kp85jgoBHa05gix6UIRjfCDiUV3w/8VIdZ247VyyO2gEjaw12WEVhdIjlxp/AMzXxqxQwbxNTDVZ3Mwd2RG5rw==} + '@biomejs/cli-win32-x64@2.5.0': + resolution: {integrity: sha512-VT/lF+GId+67j8aDfLkxdxNoVApsPSTbyAtB3jJq0IWTrY77WXfbPfpngxq0bA6JCEv/7k8C9qWjDRKRznDlyw==} engines: {node: '>=14.21.3'} cpu: [x64] os: [win32] @@ -598,9 +580,6 @@ packages: '@cwasm/webp@0.1.5': resolution: {integrity: sha512-ceIZQkyxK+s7mmItNcWqqHdOBiJAxYxTnrnPNgUNjldB1M9j+Bp/3eVIVwC8rUFyN/zoFwuT0331pyY3ackaNA==} - '@dimforge/rapier3d-compat@0.12.0': - resolution: {integrity: sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==} - '@discordjs/builders@1.14.1': resolution: {integrity: sha512-gSKkhXLqs96TCzk66VZuHHl8z2bQMJFGwrXC0f33ngK+FLNau4hU1PYny3DNJfNdSH+gVMzE85/d5FQ2BpcNwQ==} engines: {node: '>=16.11.0'} @@ -1297,17 +1276,9 @@ packages: resolution: {integrity: sha512-YLpIA5yYC4NRSaw3suitZcQUW/vdI3DHadsCZjPEgUOi2vuoPzPwq+L8Qtt4REuJs/Pw3BcypdVBQfeUVtw9sA==} engines: {node: '>=18.20.0'} - '@mediapipe/tasks-vision@0.10.17': - resolution: {integrity: sha512-CZWV/q6TTe8ta61cZXjfnnHsfWIdFhms03M9T7Cnd5y2mdpylJM0rF1qRq+wsQVRMLz1OYPVEBU9ph2Bx8cxrg==} - '@minhducsun2002/leb128@1.0.0': resolution: {integrity: sha512-eFrYUPDVHeuwWHluTG1kwNQUEUcFjVKYwPkU8z9DR1JH3AW7JtJsG9cRVGmwz809kKtGfwGJj58juCZxEvnI/g==} - '@monogrid/gainmap-js@3.4.0': - resolution: {integrity: sha512-2Z0FATFHaoYJ8b+Y4y4Hgfn3FRFwuU5zRrk+9dFWp4uGAdHGqVEdP7HP+gLA3X469KXHmfupJaUbKo1b/aDKIg==} - peerDependencies: - three: '>= 0.159.0' - '@napi-rs/cli@2.18.4': resolution: {integrity: sha512-SgJeA4df9DE2iAEpr3M2H0OKl/yjtg1BnRI5/JyowS71tUWhrfSu2LT0V3vlHET+g1hBVlrO60PmEXwUEKp8Mg==} engines: {node: '>= 10'} @@ -1747,70 +1718,6 @@ packages: '@types/react': optional: true - '@react-spring/animated@9.7.5': - resolution: {integrity: sha512-Tqrwz7pIlsSDITzxoLS3n/v/YCUHQdOIKtOJf4yL6kYVSDTSmVK1LI1Q3M/uu2Sx4X3pIWF3xLUhlsA6SPNTNg==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - - '@react-spring/core@9.7.5': - resolution: {integrity: sha512-rmEqcxRcu7dWh7MnCcMXLvrf6/SDlSokLaLTxiPlAYi11nN3B5oiCUAblO72o+9z/87j2uzxa2Inm8UbLjXA+w==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - - '@react-spring/rafz@9.7.5': - resolution: {integrity: sha512-5ZenDQMC48wjUzPAm1EtwQ5Ot3bLIAwwqP2w2owG5KoNdNHpEJV263nGhCeKKmuA3vG2zLLOdu3or6kuDjA6Aw==} - - '@react-spring/shared@9.7.5': - resolution: {integrity: sha512-wdtoJrhUeeyD/PP/zo+np2s1Z820Ohr/BbuVYv+3dVLW7WctoiN7std8rISoYoHpUXtbkpesSKuPIw/6U1w1Pw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - - '@react-spring/three@9.7.5': - resolution: {integrity: sha512-RxIsCoQfUqOS3POmhVHa1wdWS0wyHAUway73uRLp3GAL5U2iYVNdnzQsep6M2NZ994BlW8TcKuMtQHUqOsy6WA==} - peerDependencies: - '@react-three/fiber': '>=6.0' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - three: '>=0.126' - - '@react-spring/types@9.7.5': - resolution: {integrity: sha512-HVj7LrZ4ReHWBimBvu2SKND3cDVUPWKLqRTmWe/fNY6o1owGOX0cAHbdPDTMelgBlVbrTKrre6lFkhqGZErK/g==} - - '@react-three/drei@9.122.0': - resolution: {integrity: sha512-SEO/F/rBCTjlLez7WAlpys+iGe9hty4rNgjZvgkQeXFSiwqD4Hbk/wNHMAbdd8vprO2Aj81mihv4dF5bC7D0CA==} - peerDependencies: - '@react-three/fiber': ^8 - react: ^18 - react-dom: ^18 - three: '>=0.137' - peerDependenciesMeta: - react-dom: - optional: true - - '@react-three/fiber@9.6.1': - resolution: {integrity: sha512-zF0rsKcVYpcJwbFEnv2HkHX9cvOEgsfQo/X8lwmR2dn13S4qEQJXir9fxf5js2LQFoXqxOY7MDkOkYx2uZ4gSg==} - peerDependencies: - expo: '>=43.0' - expo-asset: '>=8.4' - expo-file-system: '>=11.0' - expo-gl: '>=11.0' - react: '>=19 <19.3' - react-dom: '>=19 <19.3' - react-native: '>=0.78' - three: '>=0.156' - peerDependenciesMeta: - expo: - optional: true - expo-asset: - optional: true - expo-file-system: - optional: true - expo-gl: - optional: true - react-dom: - optional: true - react-native: - optional: true - '@rolldown/binding-android-arm64@1.0.1': resolution: {integrity: sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -2168,21 +2075,10 @@ packages: '@tailwindcss/postcss@4.3.0': resolution: {integrity: sha512-Jm05Tjx+9yCLGv5qw1c+84Psds8MnyrEQYCB+FFk2lgGiUjlRqdxke4mVTuYrj2xnVZqKim2Apr5ySuQRYAw/w==} - '@tanstack/query-core@5.100.14': - resolution: {integrity: sha512-5X41dGpxgeaHISCRW2oYwcSycZeULZzAunaudXT9ov1KOTj9xwt0CH6hbwqP1/z74ZWF7rYFnDpyYH07XFcZew==} - - '@tanstack/react-query@5.100.14': - resolution: {integrity: sha512-oOr6aRdSFEwWhzxEkD/9ZcItM3+LjBSkeVmadWKwUssAHTsqd/7bOjWrX4AbvEkoEhgAxzN0Xk6H/aYzXiYBAw==} - peerDependencies: - react: ^18 || ^19 - '@tsd/typescript@5.9.3': resolution: {integrity: sha512-JSSdNiS0wgd8GHhBwnMAI18Y8XPhLVN+dNelPfZCXFhy9Lb3NbnFyp9JKxxr54jSUkEJPk3cidvCoHducSaRMQ==} engines: {node: '>=14.17'} - '@tweenjs/tween.js@23.1.3': - resolution: {integrity: sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==} - '@tybys/wasm-util@0.10.2': resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} @@ -2201,9 +2097,6 @@ packages: '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - '@types/draco3d@1.4.10': - resolution: {integrity: sha512-AX22jp8Y7wwaBgAixaSvkoG4M/+PlAcm3Qs4OW8yT9DM4xUpWKeFhLueTAyZF39pviAdcDdeJoACapiAceqNcw==} - '@types/eslint@7.29.0': resolution: {integrity: sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng==} @@ -2252,9 +2145,6 @@ packages: '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} - '@types/offscreencanvas@2019.7.3': - resolution: {integrity: sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==} - '@types/pg@8.20.0': resolution: {integrity: sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==} @@ -2269,11 +2159,6 @@ packages: peerDependencies: '@types/react': ^19.2.0 - '@types/react-reconciler@0.28.9': - resolution: {integrity: sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==} - peerDependencies: - '@types/react': '*' - '@types/react@19.2.14': resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} @@ -2283,26 +2168,9 @@ packages: '@types/serve-static@2.2.0': resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==} - '@types/stats.js@0.17.4': - resolution: {integrity: sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==} - - '@types/three@0.184.1': - resolution: {integrity: sha512-6q4VdiqVsrTRqmk62/BnlcAvIrnDM0zf2ZDVKI5kZiniWrSaOHaQzmbp+BNzoggc/8tgW412pL//wZIxu2PPTA==} - - '@types/webxr@0.5.24': - resolution: {integrity: sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==} - '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} - '@use-gesture/core@10.3.1': - resolution: {integrity: sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==} - - '@use-gesture/react@10.3.1': - resolution: {integrity: sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==} - peerDependencies: - react: '>= 16.8.0' - '@vitejs/plugin-react@6.0.2': resolution: {integrity: sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -2316,11 +2184,11 @@ packages: babel-plugin-react-compiler: optional: true - '@vitest/expect@4.1.8': - resolution: {integrity: sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==} + '@vitest/expect@4.1.9': + resolution: {integrity: sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==} - '@vitest/mocker@4.1.8': - resolution: {integrity: sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==} + '@vitest/mocker@4.1.9': + resolution: {integrity: sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -2330,20 +2198,20 @@ packages: vite: optional: true - '@vitest/pretty-format@4.1.8': - resolution: {integrity: sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==} + '@vitest/pretty-format@4.1.9': + resolution: {integrity: sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==} - '@vitest/runner@4.1.8': - resolution: {integrity: sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==} + '@vitest/runner@4.1.9': + resolution: {integrity: sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==} - '@vitest/snapshot@4.1.8': - resolution: {integrity: sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==} + '@vitest/snapshot@4.1.9': + resolution: {integrity: sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==} - '@vitest/spy@4.1.8': - resolution: {integrity: sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==} + '@vitest/spy@4.1.9': + resolution: {integrity: sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA==} - '@vitest/utils@4.1.8': - resolution: {integrity: sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==} + '@vitest/utils@4.1.9': + resolution: {integrity: sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==} '@yarnpkg/lockfile@1.1.0': resolution: {integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==} @@ -2493,9 +2361,6 @@ packages: before-after-hook@2.2.3: resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} - bidi-js@1.0.3: - resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} - bintrees@1.0.2: resolution: {integrity: sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==} @@ -2572,11 +2437,6 @@ packages: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} - camera-controls@2.10.1: - resolution: {integrity: sha512-KnaKdcvkBJ1Irbrzl8XD6WtZltkRjp869Jx8c0ujs9K+9WD+1D7ryBsCiVqJYUqt6i/HR5FxT7RLASieUD+Q5w==} - peerDependencies: - three: '>=0.126.1' - caniuse-lite@1.0.30001793: resolution: {integrity: sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==} @@ -2722,11 +2582,6 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - cross-env@7.0.3: - resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} - engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} - hasBin: true - cross-spawn@6.0.6: resolution: {integrity: sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==} engines: {node: '>=4.8'} @@ -2820,9 +2675,6 @@ packages: deprecation@2.3.1: resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} - detect-gpu@5.0.70: - resolution: {integrity: sha512-bqerEP1Ese6nt3rFkwPnGbsUF9a4q+gMmpTVVOEzoCyeCc+y7/RvJnQZJx1JwhgQI5Ntg0Kgat8Uu7XpBqnz1w==} - detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -2857,9 +2709,6 @@ packages: resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} engines: {node: '>=12'} - draco3d@1.5.7: - resolution: {integrity: sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==} - drizzle-kit@0.31.10: resolution: {integrity: sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw==} hasBin: true @@ -3168,12 +3017,6 @@ packages: fetch-cookie@3.2.0: resolution: {integrity: sha512-n61pQIxP25C6DRhcJxn7BDzgHP/+S56Urowb5WFxtcRMpU6drqXD90xjyAsVQYsNSNNVbaCcYY1DuHsdkZLuiA==} - fflate@0.6.10: - resolution: {integrity: sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==} - - fflate@0.8.3: - resolution: {integrity: sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==} - figures@3.2.0: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} @@ -3359,9 +3202,6 @@ packages: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} - glsl-noise@0.0.0: - resolution: {integrity: sha512-b/ZCF6amfAUb7dJM/MxRs7AetQEahYzJ8PtgfrmEdtw6uyGOr+ZSGtgjFm6mfsBkxJ4d2W7kg+Nlqzqvn3Bc0w==} - gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -3369,9 +3209,6 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - gsap@3.15.0: - resolution: {integrity: sha512-dMW4CWBTUK1AEEDeZc1g4xpPGIrSf9fJF960qbTZmN/QwZIWY5wgliS6JWl9/25fpTGJrMRtSjGtOmPnfjZB+A==} - handlebars@4.7.9: resolution: {integrity: sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==} engines: {node: '>=0.4.7'} @@ -3414,9 +3251,6 @@ packages: help-me@5.0.0: resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} - hls.js@1.6.16: - resolution: {integrity: sha512-VSIRpLfRwlAAdGL4wiTucx2ScRipo0ed1FBatWkyt832jC4CReKstga6yIhYVwGu9LOBjuX9wzmRMeQdBJtzEA==} - hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} @@ -3463,9 +3297,6 @@ packages: resolution: {integrity: sha512-atRI6S7rwrdZlr8pBsuk0NfBfeuPzyna98ugz2Sodj1P8SOZJLVYuqWnUrUFg2YnFTxtdbdSq4Ucn1osLFQ+qA==} engines: {node: '>=20'} - immediate@3.0.6: - resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} - import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -3558,9 +3389,6 @@ packages: resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} engines: {node: '>=0.10.0'} - is-promise@2.2.2: - resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} - is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} @@ -3600,11 +3428,6 @@ packages: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} engines: {node: '>=0.10.0'} - its-fine@2.0.0: - resolution: {integrity: sha512-KLViCmWx94zOvpLwSlsx6yOCeMhZYaxrJV87Po5k/FoZzcPSahvK5qJ7fYhS61sZi5ikmh2S3Hz55A2l3U69ng==} - peerDependencies: - react: ^19.0.0 - jest-diff@29.7.0: resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -3691,9 +3514,6 @@ packages: libsodium@0.8.4: resolution: {integrity: sha512-lMcYaRi0zcs7tarATsQUYC7rstliIXZuoq0c6zXSgNtSNtdvBgkSegjWhpMJAXzKX3SUSwIp7+zEsob+j3LuRw==} - lie@3.3.0: - resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} - lightningcss-android-arm64@1.32.0: resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} engines: {node: '>= 12.0.0'} @@ -3806,10 +3626,6 @@ packages: resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==} engines: {node: '>= 0.6.0'} - loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true - lru-cache@11.5.1: resolution: {integrity: sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==} engines: {node: 20 || >=22} @@ -3823,12 +3639,6 @@ packages: peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - maath@0.10.8: - resolution: {integrity: sha512-tRvbDF0Pgqz+9XUa4jjfgAQ8/aPKmQdWXilFu2tMy4GWj4NOsx99HlULO4IeREfbO3a0sA145DZYyvXPkybm0g==} - peerDependencies: - '@types/three': '>=0.134.0' - three: '>=0.134.0' - magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -3891,14 +3701,6 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - meshline@3.3.1: - resolution: {integrity: sha512-/TQj+JdZkeSUOl5Mk2J7eLcYTLiQm2IDzmlSvYm7ov15anEcDJ92GHqqazxTSreeNgfnYu24kiEvvv0WlbCdFQ==} - peerDependencies: - three: '>=0.137' - - meshoptimizer@1.1.1: - resolution: {integrity: sha512-oRFNWJRDA/WTrVj7NWvqa5HqE1t9MYDj2VaWirQCzCCrAd2GHrqR/sQezCxiWATPNlKTcRaPRHPJwIRoPBAp5g==} - micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -4324,9 +4126,6 @@ packages: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} engines: {node: '>=0.10.0'} - potpack@1.0.2: - resolution: {integrity: sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==} - prebuild-install@7.1.3: resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} engines: {node: '>=10'} @@ -4379,12 +4178,6 @@ packages: resolution: {integrity: sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g==} engines: {node: ^16 || ^18 || >=20} - promise-worker-transferable@1.0.4: - resolution: {integrity: sha512-bN+0ehEnrXfxV2ZQvU2PetO0n4gqBD4ulq3MI1WOPLgr7/Mg9yRQkX5+0v1vagr74ZTsl7XtzlaYDo2EuCeYJw==} - - prop-types@15.8.1: - resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -4450,31 +4243,14 @@ packages: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true - react-composer@5.0.3: - resolution: {integrity: sha512-1uWd07EME6XZvMfapwZmc7NgCZqDemcvicRi3wMJzXsQLvZ3L7fTHVyPy1bZdnWXM4iPjYuNE+uJ41MLKeTtnA==} - peerDependencies: - react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 - react-dom@19.2.6: resolution: {integrity: sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==} peerDependencies: react: ^19.2.6 - react-is@16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - react-use-measure@2.1.7: - resolution: {integrity: sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==} - peerDependencies: - react: '>=16.13' - react-dom: '>=16.13' - peerDependenciesMeta: - react-dom: - optional: true - react@19.2.6: resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==} engines: {node: '>=0.10.0'} @@ -4541,10 +4317,6 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} - require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - require-main-filename@2.0.0: resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} @@ -4768,15 +4540,6 @@ packages: standard-as-callback@2.1.0: resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} - stats-gl@2.4.2: - resolution: {integrity: sha512-g5O9B0hm9CvnM36+v7SFl39T7hmAlv541tU81ME8YeSb3i1CIP5/QdDeSB3A0la0bKNHpxpwxOVRo2wFTYEosQ==} - peerDependencies: - '@types/three': '*' - three: '*' - - stats.js@0.17.0: - resolution: {integrity: sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==} - statuses@2.0.2: resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} engines: {node: '>= 0.8'} @@ -4855,11 +4618,6 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - suspend-react@0.1.3: - resolution: {integrity: sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==} - peerDependencies: - react: '>=17.0' - table-layout@0.4.5: resolution: {integrity: sha512-zTvf0mcggrGeTe/2jJ6ECkJHAQPIYEwDoqsiqBjI24mvRmQbInK5jq33fyypaCBxX08hMkfmdOqj6haT33EqWw==} engines: {node: '>=4.0.0'} @@ -4924,20 +4682,6 @@ packages: thread-stream@3.1.0: resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} - three-mesh-bvh@0.7.8: - resolution: {integrity: sha512-BGEZTOIC14U0XIRw3tO4jY7IjP7n7v24nv9JXS1CyeVRWOCkcOMhRnmENUjuV39gktAw4Ofhr0OvIAiTspQrrw==} - deprecated: Deprecated due to three.js version incompatibility. Please use v0.8.0, instead. - peerDependencies: - three: '>= 0.151.0' - - three-stdlib@2.36.1: - resolution: {integrity: sha512-XyGQrFmNQ5O/IoKm556ftwKsBg11TIb301MB5dWNicziQBEs2g3gtOYIf7pFiLa0zI2gUwhtCjv9fmjnxKZ1Cg==} - peerDependencies: - three: '>=0.128.0' - - three@0.174.0: - resolution: {integrity: sha512-p+WG3W6Ov74alh3geCMkGK9NWuT62ee21cV3jEnun201zodVF4tCE5aZa2U122/mkLRmhJJUQmLLW1BH00uQJQ==} - through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} @@ -5014,19 +4758,6 @@ packages: resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} engines: {node: '>=8'} - troika-three-text@0.52.4: - resolution: {integrity: sha512-V50EwcYGruV5rUZ9F4aNsrytGdKcXKALjEtQXIOBfhVoZU9VAqZNIoGQ3TMiooVqFAbR1w15T+f+8gkzoFzawg==} - peerDependencies: - three: '>=0.125.0' - - troika-three-utils@0.52.4: - resolution: {integrity: sha512-NORAStSVa/BDiG52Mfudk4j1FG4jC4ILutB3foPnfGbOeIs9+G5vZLa0pnmnaftZUGm4UwSoqEpWdqvC7zms3A==} - peerDependencies: - three: '>=0.125.0' - - troika-worker-utils@0.52.0: - resolution: {integrity: sha512-W1CpvTHykaPH5brv5VHLfQo9D1OYuo0cSBEUQFFT/nBUzM8iD6Lq2/tgG/f1OelbAS1WtaTPQzE5uM49egnngw==} - ts-mixer@6.0.4: resolution: {integrity: sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==} @@ -5062,9 +4793,6 @@ packages: tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} - tunnel-rat@0.1.2: - resolution: {integrity: sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ==} - tunnel@0.0.6: resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} @@ -5175,18 +4903,9 @@ packages: resolution: {integrity: sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - use-sync-external-store@1.6.0: - resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - utility-types@3.11.0: - resolution: {integrity: sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==} - engines: {node: '>= 4'} - v8-compile-cache@2.4.0: resolution: {integrity: sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==} @@ -5244,20 +4963,20 @@ packages: yaml: optional: true - vitest@4.1.8: - resolution: {integrity: sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==} + vitest@4.1.9: + resolution: {integrity: sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.8 - '@vitest/browser-preview': 4.1.8 - '@vitest/browser-webdriverio': 4.1.8 - '@vitest/coverage-istanbul': 4.1.8 - '@vitest/coverage-v8': 4.1.8 - '@vitest/ui': 4.1.8 + '@vitest/browser-playwright': 4.1.9 + '@vitest/browser-preview': 4.1.9 + '@vitest/browser-webdriverio': 4.1.9 + '@vitest/coverage-istanbul': 4.1.9 + '@vitest/coverage-v8': 4.1.9 + '@vitest/ui': 4.1.9 happy-dom: '*' jsdom: '*' vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -5297,12 +5016,6 @@ packages: resolution: {integrity: sha512-kudCA8PXVQfrqv2mFTG72vDBRi8BKWxGgFLwPpzHcpZnSwZk93WMwUDVcLHWNsnm+Y0AC4Vb6MUNRgaHfyV2DQ==} engines: {node: '>=8.0.0'} - webgl-constants@1.1.1: - resolution: {integrity: sha512-LkBXKjU5r9vAW7Gcu3T5u+5cvSvh5WwINdr0C+9jpzVB41cjQAP5ePArDtk/WHYdVj0GefCgM73BA7FlIiNtdg==} - - webgl-sdf-generator@1.1.1: - resolution: {integrity: sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==} - webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -5448,39 +5161,6 @@ packages: zod@4.4.3: resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} - zustand@4.5.7: - resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==} - engines: {node: '>=12.7.0'} - peerDependencies: - '@types/react': '>=16.8' - immer: '>=9.0.6' - react: '>=16.8' - peerDependenciesMeta: - '@types/react': - optional: true - immer: - optional: true - react: - optional: true - - zustand@5.0.14: - resolution: {integrity: sha512-/8tAspM5LMPr28b3fwLYrtdj77ECpfZviaP75CMTnwO8ISyaE4GDIG/9rDDYq/cH9D2Xw2A2RXglLInmVBQB/g==} - engines: {node: '>=12.20.0'} - peerDependencies: - '@types/react': '>=18.0.0' - immer: '>=9.0.6' - react: '>=18.0.0' - use-sync-external-store: '>=1.2.0' - peerDependenciesMeta: - '@types/react': - optional: true - immer: - optional: true - react: - optional: true - use-sync-external-store: - optional: true - snapshots: '@actions/core@1.11.1': @@ -5533,63 +5213,63 @@ snapshots: '@biomejs/cli-win32-arm64': 2.3.8 '@biomejs/cli-win32-x64': 2.3.8 - '@biomejs/biome@2.4.16': + '@biomejs/biome@2.5.0': optionalDependencies: - '@biomejs/cli-darwin-arm64': 2.4.16 - '@biomejs/cli-darwin-x64': 2.4.16 - '@biomejs/cli-linux-arm64': 2.4.16 - '@biomejs/cli-linux-arm64-musl': 2.4.16 - '@biomejs/cli-linux-x64': 2.4.16 - '@biomejs/cli-linux-x64-musl': 2.4.16 - '@biomejs/cli-win32-arm64': 2.4.16 - '@biomejs/cli-win32-x64': 2.4.16 + '@biomejs/cli-darwin-arm64': 2.5.0 + '@biomejs/cli-darwin-x64': 2.5.0 + '@biomejs/cli-linux-arm64': 2.5.0 + '@biomejs/cli-linux-arm64-musl': 2.5.0 + '@biomejs/cli-linux-x64': 2.5.0 + '@biomejs/cli-linux-x64-musl': 2.5.0 + '@biomejs/cli-win32-arm64': 2.5.0 + '@biomejs/cli-win32-x64': 2.5.0 '@biomejs/cli-darwin-arm64@2.3.8': optional: true - '@biomejs/cli-darwin-arm64@2.4.16': + '@biomejs/cli-darwin-arm64@2.5.0': optional: true '@biomejs/cli-darwin-x64@2.3.8': optional: true - '@biomejs/cli-darwin-x64@2.4.16': + '@biomejs/cli-darwin-x64@2.5.0': optional: true '@biomejs/cli-linux-arm64-musl@2.3.8': optional: true - '@biomejs/cli-linux-arm64-musl@2.4.16': + '@biomejs/cli-linux-arm64-musl@2.5.0': optional: true '@biomejs/cli-linux-arm64@2.3.8': optional: true - '@biomejs/cli-linux-arm64@2.4.16': + '@biomejs/cli-linux-arm64@2.5.0': optional: true '@biomejs/cli-linux-x64-musl@2.3.8': optional: true - '@biomejs/cli-linux-x64-musl@2.4.16': + '@biomejs/cli-linux-x64-musl@2.5.0': optional: true '@biomejs/cli-linux-x64@2.3.8': optional: true - '@biomejs/cli-linux-x64@2.4.16': + '@biomejs/cli-linux-x64@2.5.0': optional: true '@biomejs/cli-win32-arm64@2.3.8': optional: true - '@biomejs/cli-win32-arm64@2.4.16': + '@biomejs/cli-win32-arm64@2.5.0': optional: true '@biomejs/cli-win32-x64@2.3.8': optional: true - '@biomejs/cli-win32-x64@2.4.16': + '@biomejs/cli-win32-x64@2.5.0': optional: true '@canvas/image-data@1.1.0': {} @@ -5628,8 +5308,6 @@ snapshots: dependencies: '@canvas/image-data': 1.1.0 - '@dimforge/rapier3d-compat@0.12.0': {} - '@discordjs/builders@1.14.1': dependencies: '@discordjs/formatters': 0.6.2 @@ -6094,15 +5772,8 @@ snapshots: dependencies: prebuild-install: 7.1.3 - '@mediapipe/tasks-vision@0.10.17': {} - '@minhducsun2002/leb128@1.0.0': {} - '@monogrid/gainmap-js@3.4.0(three@0.174.0)': - dependencies: - promise-worker-transferable: 1.0.4 - three: 0.174.0 - '@napi-rs/cli@2.18.4': {} '@napi-rs/nice-android-arm-eabi@1.1.1': @@ -6548,94 +6219,6 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 - '@react-spring/animated@9.7.5(react@19.2.6)': - dependencies: - '@react-spring/shared': 9.7.5(react@19.2.6) - '@react-spring/types': 9.7.5 - react: 19.2.6 - - '@react-spring/core@9.7.5(react@19.2.6)': - dependencies: - '@react-spring/animated': 9.7.5(react@19.2.6) - '@react-spring/shared': 9.7.5(react@19.2.6) - '@react-spring/types': 9.7.5 - react: 19.2.6 - - '@react-spring/rafz@9.7.5': {} - - '@react-spring/shared@9.7.5(react@19.2.6)': - dependencies: - '@react-spring/rafz': 9.7.5 - '@react-spring/types': 9.7.5 - react: 19.2.6 - - '@react-spring/three@9.7.5(@react-three/fiber@9.6.1(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(three@0.174.0))(react@19.2.6)(three@0.174.0)': - dependencies: - '@react-spring/animated': 9.7.5(react@19.2.6) - '@react-spring/core': 9.7.5(react@19.2.6) - '@react-spring/shared': 9.7.5(react@19.2.6) - '@react-spring/types': 9.7.5 - '@react-three/fiber': 9.6.1(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(three@0.174.0) - react: 19.2.6 - three: 0.174.0 - - '@react-spring/types@9.7.5': {} - - '@react-three/drei@9.122.0(@react-three/fiber@9.6.1(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(three@0.174.0))(@types/react@19.2.14)(@types/three@0.184.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(three@0.174.0)(use-sync-external-store@1.6.0(react@19.2.6))': - dependencies: - '@babel/runtime': 7.29.2 - '@mediapipe/tasks-vision': 0.10.17 - '@monogrid/gainmap-js': 3.4.0(three@0.174.0) - '@react-spring/three': 9.7.5(@react-three/fiber@9.6.1(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(three@0.174.0))(react@19.2.6)(three@0.174.0) - '@react-three/fiber': 9.6.1(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(three@0.174.0) - '@use-gesture/react': 10.3.1(react@19.2.6) - camera-controls: 2.10.1(three@0.174.0) - cross-env: 7.0.3 - detect-gpu: 5.0.70 - glsl-noise: 0.0.0 - hls.js: 1.6.16 - maath: 0.10.8(@types/three@0.184.1)(three@0.174.0) - meshline: 3.3.1(three@0.174.0) - react: 19.2.6 - react-composer: 5.0.3(react@19.2.6) - stats-gl: 2.4.2(@types/three@0.184.1)(three@0.174.0) - stats.js: 0.17.0 - suspend-react: 0.1.3(react@19.2.6) - three: 0.174.0 - three-mesh-bvh: 0.7.8(three@0.174.0) - three-stdlib: 2.36.1(three@0.174.0) - troika-three-text: 0.52.4(three@0.174.0) - tunnel-rat: 0.1.2(@types/react@19.2.14)(react@19.2.6) - utility-types: 3.11.0 - zustand: 5.0.14(@types/react@19.2.14)(react@19.2.6)(use-sync-external-store@1.6.0(react@19.2.6)) - optionalDependencies: - react-dom: 19.2.6(react@19.2.6) - transitivePeerDependencies: - - '@types/react' - - '@types/three' - - immer - - use-sync-external-store - - '@react-three/fiber@9.6.1(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(three@0.174.0)': - dependencies: - '@babel/runtime': 7.29.2 - '@types/webxr': 0.5.24 - base64-js: 1.5.1 - buffer: 6.0.3 - its-fine: 2.0.0(@types/react@19.2.14)(react@19.2.6) - react: 19.2.6 - react-use-measure: 2.1.7(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - scheduler: 0.27.0 - suspend-react: 0.1.3(react@19.2.6) - three: 0.174.0 - use-sync-external-store: 1.6.0(react@19.2.6) - zustand: 5.0.14(@types/react@19.2.14)(react@19.2.6)(use-sync-external-store@1.6.0(react@19.2.6)) - optionalDependencies: - react-dom: 19.2.6(react@19.2.6) - transitivePeerDependencies: - - '@types/react' - - immer - '@rolldown/binding-android-arm64@1.0.1': optional: true @@ -6869,17 +6452,8 @@ snapshots: postcss: 8.5.14 tailwindcss: 4.3.0 - '@tanstack/query-core@5.100.14': {} - - '@tanstack/react-query@5.100.14(react@19.2.6)': - dependencies: - '@tanstack/query-core': 5.100.14 - react: 19.2.6 - '@tsd/typescript@5.9.3': {} - '@tweenjs/tween.js@23.1.3': {} - '@tybys/wasm-util@0.10.2': dependencies: tslib: 2.8.1 @@ -6905,8 +6479,6 @@ snapshots: '@types/deep-eql@4.0.2': {} - '@types/draco3d@1.4.10': {} - '@types/eslint@7.29.0': dependencies: '@types/estree': 1.0.9 @@ -6962,8 +6534,6 @@ snapshots: '@types/normalize-package-data@2.4.4': {} - '@types/offscreencanvas@2019.7.3': {} - '@types/pg@8.20.0': dependencies: '@types/node': 25.8.0 @@ -6978,10 +6548,6 @@ snapshots: dependencies: '@types/react': 19.2.14 - '@types/react-reconciler@0.28.9(@types/react@19.2.14)': - dependencies: - '@types/react': 19.2.14 - '@types/react@19.2.14': dependencies: csstype: 3.2.3 @@ -6995,73 +6561,53 @@ snapshots: '@types/http-errors': 2.0.5 '@types/node': 25.9.0 - '@types/stats.js@0.17.4': {} - - '@types/three@0.184.1': - dependencies: - '@dimforge/rapier3d-compat': 0.12.0 - '@tweenjs/tween.js': 23.1.3 - '@types/stats.js': 0.17.4 - '@types/webxr': 0.5.24 - fflate: 0.8.3 - meshoptimizer: 1.1.1 - - '@types/webxr@0.5.24': {} - '@types/ws@8.18.1': dependencies: '@types/node': 25.8.0 - '@use-gesture/core@10.3.1': {} - - '@use-gesture/react@10.3.1(react@19.2.6)': - dependencies: - '@use-gesture/core': 10.3.1 - react: 19.2.6 - '@vitejs/plugin-react@6.0.2(vite@8.0.13(@types/node@25.9.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0))': dependencies: '@rolldown/pluginutils': 1.0.1 vite: 8.0.13(@types/node@25.9.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0) - '@vitest/expect@4.1.8': + '@vitest/expect@4.1.9': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.1.8 - '@vitest/utils': 4.1.8 + '@vitest/spy': 4.1.9 + '@vitest/utils': 4.1.9 chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.8(vite@8.0.13(@types/node@25.9.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0))': + '@vitest/mocker@4.1.9(vite@8.0.13(@types/node@25.9.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0))': dependencies: - '@vitest/spy': 4.1.8 + '@vitest/spy': 4.1.9 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: vite: 8.0.13(@types/node@25.9.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0) - '@vitest/pretty-format@4.1.8': + '@vitest/pretty-format@4.1.9': dependencies: tinyrainbow: 3.1.0 - '@vitest/runner@4.1.8': + '@vitest/runner@4.1.9': dependencies: - '@vitest/utils': 4.1.8 + '@vitest/utils': 4.1.9 pathe: 2.0.3 - '@vitest/snapshot@4.1.8': + '@vitest/snapshot@4.1.9': dependencies: - '@vitest/pretty-format': 4.1.8 - '@vitest/utils': 4.1.8 + '@vitest/pretty-format': 4.1.9 + '@vitest/utils': 4.1.9 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.1.8': {} + '@vitest/spy@4.1.9': {} - '@vitest/utils@4.1.8': + '@vitest/utils@4.1.9': dependencies: - '@vitest/pretty-format': 4.1.8 + '@vitest/pretty-format': 4.1.9 convert-source-map: 2.0.0 tinyrainbow: 3.1.0 @@ -7191,10 +6737,6 @@ snapshots: before-after-hook@2.2.3: {} - bidi-js@1.0.3: - dependencies: - require-from-string: 2.0.2 - bintrees@1.0.2: {} bl@4.1.0: @@ -7289,10 +6831,6 @@ snapshots: camelcase@5.3.1: {} - camera-controls@2.10.1(three@0.174.0): - dependencies: - three: 0.174.0 - caniuse-lite@1.0.30001793: {} catharsis@0.9.0: @@ -7419,10 +6957,6 @@ snapshots: core-util-is@1.0.3: {} - cross-env@7.0.3: - dependencies: - cross-spawn: 7.0.6 - cross-spawn@6.0.6: dependencies: nice-try: 1.0.5 @@ -7511,10 +7045,6 @@ snapshots: deprecation@2.3.1: {} - detect-gpu@5.0.70: - dependencies: - webgl-constants: 1.1.1 - detect-libc@2.1.2: {} diff-sequences@29.6.3: {} @@ -7552,8 +7082,6 @@ snapshots: dotenv@17.4.2: {} - draco3d@1.5.7: {} - drizzle-kit@0.31.10: dependencies: '@drizzle-team/brocli': 0.10.2 @@ -7901,10 +7429,6 @@ snapshots: set-cookie-parser: 2.7.2 tough-cookie: 6.0.1 - fflate@0.6.10: {} - - fflate@0.8.3: {} - figures@3.2.0: dependencies: escape-string-regexp: 1.0.5 @@ -8111,14 +7635,10 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 - glsl-noise@0.0.0: {} - gopd@1.2.0: {} graceful-fs@4.2.11: {} - gsap@3.15.0: {} - handlebars@4.7.9: dependencies: minimist: 1.2.8 @@ -8154,8 +7674,6 @@ snapshots: help-me@5.0.0: {} - hls.js@1.6.16: {} - hosted-git-info@2.8.9: {} hosted-git-info@4.1.0: @@ -8204,8 +7722,6 @@ snapshots: image-type: 4.1.0 jpeg-js: 0.4.4 - immediate@3.0.6: {} - import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -8290,8 +7806,6 @@ snapshots: dependencies: isobject: 3.0.1 - is-promise@2.2.2: {} - is-promise@4.0.0: {} is-property@1.0.2: {} @@ -8316,13 +7830,6 @@ snapshots: isobject@3.0.1: {} - its-fine@2.0.0(@types/react@19.2.14)(react@19.2.6): - dependencies: - '@types/react-reconciler': 0.28.9(@types/react@19.2.14) - react: 19.2.6 - transitivePeerDependencies: - - '@types/react' - jest-diff@29.7.0: dependencies: chalk: 4.1.2 @@ -8441,10 +7948,6 @@ snapshots: libsodium@0.8.4: {} - lie@3.3.0: - dependencies: - immediate: 3.0.6 - lightningcss-android-arm64@1.32.0: optional: true @@ -8526,10 +8029,6 @@ snapshots: loglevel@1.9.2: {} - loose-envify@1.4.0: - dependencies: - js-tokens: 4.0.0 - lru-cache@11.5.1: {} lru-cache@6.0.0: @@ -8540,11 +8039,6 @@ snapshots: dependencies: react: 19.2.6 - maath@0.10.8(@types/three@0.184.1)(three@0.174.0): - dependencies: - '@types/three': 0.184.1 - three: 0.174.0 - magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -8601,12 +8095,6 @@ snapshots: merge2@1.4.1: {} - meshline@3.3.1(three@0.174.0): - dependencies: - three: 0.174.0 - - meshoptimizer@1.1.1: {} - micromatch@4.0.8: dependencies: braces: 3.0.3 @@ -9025,8 +8513,6 @@ snapshots: dependencies: xtend: 4.0.2 - potpack@1.0.2: {} - prebuild-install@7.1.3: dependencies: detect-libc: 2.1.2 @@ -9074,17 +8560,6 @@ snapshots: '@opentelemetry/api': 1.9.1 tdigest: 0.1.2 - promise-worker-transferable@1.0.4: - dependencies: - is-promise: 2.2.2 - lie: 3.3.0 - - prop-types@15.8.1: - dependencies: - loose-envify: 1.4.0 - object-assign: 4.1.1 - react-is: 16.13.1 - proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -9154,26 +8629,13 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-composer@5.0.3(react@19.2.6): - dependencies: - prop-types: 15.8.1 - react: 19.2.6 - react-dom@19.2.6(react@19.2.6): dependencies: react: 19.2.6 scheduler: 0.27.0 - react-is@16.13.1: {} - react-is@18.3.1: {} - react-use-measure@2.1.7(react-dom@19.2.6(react@19.2.6))(react@19.2.6): - dependencies: - react: 19.2.6 - optionalDependencies: - react-dom: 19.2.6(react@19.2.6) - react@19.2.6: {} read-pkg-up@7.0.1: @@ -9238,8 +8700,6 @@ snapshots: require-directory@2.1.1: {} - require-from-string@2.0.2: {} - require-main-filename@2.0.0: {} requizzle@0.2.4: @@ -9511,13 +8971,6 @@ snapshots: standard-as-callback@2.1.0: {} - stats-gl@2.4.2(@types/three@0.184.1)(three@0.174.0): - dependencies: - '@types/three': 0.184.1 - three: 0.174.0 - - stats.js@0.17.0: {} - statuses@2.0.2: {} std-env@4.1.0: {} @@ -9585,10 +9038,6 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - suspend-react@0.1.3(react@19.2.6): - dependencies: - react: 19.2.6 - table-layout@0.4.5: dependencies: array-back: 2.0.0 @@ -9665,22 +9114,6 @@ snapshots: dependencies: real-require: 0.2.0 - three-mesh-bvh@0.7.8(three@0.174.0): - dependencies: - three: 0.174.0 - - three-stdlib@2.36.1(three@0.174.0): - dependencies: - '@types/draco3d': 1.4.10 - '@types/offscreencanvas': 2019.7.3 - '@types/webxr': 0.5.24 - draco3d: 1.5.7 - fflate: 0.6.10 - potpack: 1.0.2 - three: 0.174.0 - - three@0.174.0: {} - through@2.3.8: {} thunky@1.1.0: {} @@ -9738,20 +9171,6 @@ snapshots: trim-newlines@3.0.1: {} - troika-three-text@0.52.4(three@0.174.0): - dependencies: - bidi-js: 1.0.3 - three: 0.174.0 - troika-three-utils: 0.52.4(three@0.174.0) - troika-worker-utils: 0.52.0 - webgl-sdf-generator: 1.1.1 - - troika-three-utils@0.52.4(three@0.174.0): - dependencies: - three: 0.174.0 - - troika-worker-utils@0.52.0: {} - ts-mixer@6.0.4: {} tsd@0.33.0: @@ -9790,14 +9209,6 @@ snapshots: dependencies: safe-buffer: 5.2.1 - tunnel-rat@0.1.2(@types/react@19.2.14)(react@19.2.6): - dependencies: - zustand: 4.5.7(@types/react@19.2.14)(react@19.2.6) - transitivePeerDependencies: - - '@types/react' - - immer - - react - tunnel@0.0.6: {} tweetnacl@1.0.3: {} @@ -9877,14 +9288,8 @@ snapshots: url-join@5.0.0: {} - use-sync-external-store@1.6.0(react@19.2.6): - dependencies: - react: 19.2.6 - util-deprecate@1.0.2: {} - utility-types@3.11.0: {} - v8-compile-cache@2.4.0: {} validate-npm-package-license@3.0.4: @@ -9911,15 +9316,15 @@ snapshots: tsx: 4.22.2 yaml: 2.9.0 - vitest@4.1.8(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(vite@8.0.13(@types/node@25.9.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0)): + vitest@4.1.9(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(vite@8.0.13(@types/node@25.9.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0)): dependencies: - '@vitest/expect': 4.1.8 - '@vitest/mocker': 4.1.8(vite@8.0.13(@types/node@25.9.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0)) - '@vitest/pretty-format': 4.1.8 - '@vitest/runner': 4.1.8 - '@vitest/snapshot': 4.1.8 - '@vitest/spy': 4.1.8 - '@vitest/utils': 4.1.8 + '@vitest/expect': 4.1.9 + '@vitest/mocker': 4.1.9(vite@8.0.13(@types/node@25.9.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.2)(yaml@2.9.0)) + '@vitest/pretty-format': 4.1.9 + '@vitest/runner': 4.1.9 + '@vitest/snapshot': 4.1.9 + '@vitest/spy': 4.1.9 + '@vitest/utils': 4.1.9 es-module-lexer: 2.1.0 expect-type: 1.3.0 magic-string: 0.30.21 @@ -9945,10 +9350,6 @@ snapshots: walk-back@4.0.0: {} - webgl-constants@1.1.1: {} - - webgl-sdf-generator@1.1.1: {} - webidl-conversions@3.0.1: {} werift-common@0.0.3: @@ -10139,16 +9540,3 @@ snapshots: zod@3.25.76: {} zod@4.4.3: {} - - zustand@4.5.7(@types/react@19.2.14)(react@19.2.6): - dependencies: - use-sync-external-store: 1.6.0(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.14 - react: 19.2.6 - - zustand@5.0.14(@types/react@19.2.14)(react@19.2.6)(use-sync-external-store@1.6.0(react@19.2.6)): - optionalDependencies: - '@types/react': 19.2.14 - react: 19.2.6 - use-sync-external-store: 1.6.0(react@19.2.6) diff --git a/services/frontend/package.json b/services/frontend/package.json index 5632a4c..ac6e87f 100644 --- a/services/frontend/package.json +++ b/services/frontend/package.json @@ -16,24 +16,18 @@ "@radix-ui/react-scroll-area": "^1.2.10", "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-tabs": "^1.1.13", - "@react-three/drei": "^9.6.1", - "@react-three/fiber": "^9.6.1", - "@tanstack/react-query": "^5.100.14", "clsx": "^2.1.1", "framer-motion": "^12.4.0", - "gsap": "^3.12.7", "lucide-react": "^1.16.0", "react": "^19.2.6", "react-dom": "^19.2.6", - "tailwind-merge": "^3.6.0", - "three": "^0.174.0" + "tailwind-merge": "^3.6.0" }, "devDependencies": { "@biomejs/biome": "latest", "@tailwindcss/postcss": "^4.3.0", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", - "@types/three": "^0.184.1", "@vitejs/plugin-react": "^6.0.2", "autoprefixer": "^10.5.0", "postcss": "^8.5.14", diff --git a/services/frontend/src/App.tsx b/services/frontend/src/App.tsx index e521746..4f70ec8 100644 --- a/services/frontend/src/App.tsx +++ b/services/frontend/src/App.tsx @@ -1,4 +1,5 @@ import { useEffect, useMemo, useState } from "react"; +import type { ActiveSpeaker } from "./entities/voice/types.js"; import { DashboardPanel } from "./features/dashboard"; import { LivePanel } from "./features/live"; import { useMediaControl } from "./features/live/hooks/useMediaControl"; @@ -9,12 +10,7 @@ import { mergeMessages, useMessages, } from "./features/messages/hooks/useMessages"; -import { - type ActiveSpeaker, - getAppConfig, - type MediaState, - type MessageRecord, -} from "./shared/api/client"; +import { getAppConfig } from "./shared/api/client"; import { useAudioPlayback } from "./shared/hooks/useAudioPlayback"; import { useAudioTransmit } from "./shared/hooks/useAudioTransmit"; import { useUIState } from "./shared/hooks/useUIState"; @@ -74,29 +70,20 @@ export default function App() { onBinary: (d) => audio.handleIncomingBinary(d), onUserState: (users) => setActiveSpeakers( - (users as (ActiveSpeaker & { heardAt?: number })[]).map((u) => ({ + users.map((u) => ({ ...u, heardAt: Date.now(), })), ), onVoiceActiveUser: (data) => { - const d = data as { - userId?: string; - id?: string; - username: string; - avatar: string; - speaking: boolean; - }; - if (d.userId) audio.registerUserId(d.userId); + if (data.userId) audio.registerUserId(data.userId); setActiveSpeakers((prev) => - updateSpeakerList( - prev, - d as Partial & { - userId?: string; - id?: string; - speaking: boolean; - }, - ), + updateSpeakerList(prev, { + userId: data.userId, + username: data.username, + avatar: data.avatar, + speaking: data.speaking, + }), ); }, onVoiceRecordingStarted: () => @@ -104,25 +91,19 @@ export default function App() { onVoiceRecordingStopped: () => window.dispatchEvent(new CustomEvent("voice_recording_uploaded")), onMessageCreated: (m) => - messages.setMessages((prev) => mergeMessages(prev, [m as MessageRecord])), - onMessageUpdated: (m) => { - const d = m as Partial & { id: string }; + messages.setMessages((prev) => mergeMessages(prev, [m])), + onMessageUpdated: (m) => messages.setMessages((prev) => - prev.map((i) => (i.id === d.id ? { ...i, ...d } : i)), - ); - }, - onMessageDeleted: (m) => { - const d = m as { id: string }; + prev.map((i) => (i.id === m.id ? { ...i, ...m } : i)), + ), + onMessageDeleted: (m) => messages.setMessages((prev) => prev.map((i) => - i.id === d.id ? { ...i, type: "deleted" as const } : i, + i.id === m.id ? { ...i, type: "deleted" as const } : i, ), - ); - }, - onMessageAnalyzed: (m) => { - const msg = m as MessageRecord; + ), + onMessageAnalyzed: (msg) => { messages.setMessages((prev) => mergeMessages(prev, [msg])); - // Show toast for moderation alerts (flagged) const status = msg.ai_status; if (status === "flagged") { const username = msg.username || msg.user_id || "unknown"; @@ -144,7 +125,7 @@ export default function App() { messages .fetchMessages(monitorGuildId || undefined) .catch(() => undefined), - onMediaState: (state) => media.setMediaState(state as MediaState), + onMediaState: (state) => media.setMediaState(state), onVoiceRecordingUploaded: (d) => window.dispatchEvent( new CustomEvent("voice_recording_uploaded", { detail: d }), diff --git a/services/frontend/src/entities/dashboard/types.ts b/services/frontend/src/entities/dashboard/types.ts new file mode 100644 index 0000000..35af6c3 --- /dev/null +++ b/services/frontend/src/entities/dashboard/types.ts @@ -0,0 +1,75 @@ +export interface DashboardStats { + total_messages: number; + total_users: number; + total_flagged: number; + total_clean: number; + total_warned: number; + total_error: number; + total_voice_recordings: number; + total_profiles: number; + today_messages: number; + today_flagged: number; + active_users_24h: number; + top_channels: Array<{ + channel_id: string; + channel_name: string | null; + message_count: number; + }>; + moderation_overview: { + pending: number; + processing: number; + error: number; + }; +} + +export interface DashboardUser { + user_id: string; + username: string | null; + avatar_url: string | null; + profile_summary: string | null; + total_messages: number; + flagged_count: number; + last_message_at: number | null; + trust_score: number | null; +} + +export interface DashboardUserDetail extends DashboardUser { + last_analyzed_at: number | null; + clean_message_streak: number | null; + total_infractions: number | null; + clean_count: number; + recent_messages: Array<{ + id: string; + content: string; + channel_id: string; + created_at: number; + ai_status: string | null; + }>; +} + +export interface DashboardChannel { + channel_id: string; + channel_name: string | null; + guild_id: string | null; + total_messages: number; + flagged_count: number; + last_message_at: number | null; + culture_summary: string | null; + last_analyzed_at: number | null; +} + +export interface DashboardChannelDetail extends DashboardChannel { + clean_count: number; + recent_messages: Array<{ + id: string; + content: string; + channel_id: string; + created_at: number; + ai_status: string | null; + username: string | null; + }>; +} + +export interface ChatResponse { + response?: string; +} diff --git a/services/frontend/src/entities/guild/types.ts b/services/frontend/src/entities/guild/types.ts new file mode 100644 index 0000000..38ddbc9 --- /dev/null +++ b/services/frontend/src/entities/guild/types.ts @@ -0,0 +1,19 @@ +export interface Guild { + id: string; + name: string; + icon: string | null; +} + +export interface Channel { + id: string; + name: string; + type?: string; + parentId?: string | null; +} + +export interface GuildVoiceEntry { + guildId: string; + channelId: string; + channelName: string; + connectedAt: number; +} diff --git a/services/frontend/src/entities/media/types.ts b/services/frontend/src/entities/media/types.ts new file mode 100644 index 0000000..838f2e8 --- /dev/null +++ b/services/frontend/src/entities/media/types.ts @@ -0,0 +1,17 @@ +export type MediaMode = "music" | "screen"; + +export interface MediaItem { + id?: string; + source: string; + title: string; + mode?: "music" | "screen"; + durationMs?: number | null; + thumbnailUrl?: string | null; +} + +export interface MediaState { + playing: boolean; + musicVolume: number; + current: MediaItem | null; + queue: MediaItem[]; +} diff --git a/services/frontend/src/entities/message/types.ts b/services/frontend/src/entities/message/types.ts index 4bfa826..2d58789 100644 --- a/services/frontend/src/entities/message/types.ts +++ b/services/frontend/src/entities/message/types.ts @@ -17,13 +17,3 @@ export interface MessageMetadata { threadName?: string; }; } - -export function parseMetadata(value: string | null): MessageMetadata { - if (!value) return {}; - try { - const parsed = JSON.parse(value) as MessageMetadata; - return parsed; - } catch { - return {}; - } -} diff --git a/services/frontend/src/entities/recording/types.ts b/services/frontend/src/entities/recording/types.ts new file mode 100644 index 0000000..cb688cb --- /dev/null +++ b/services/frontend/src/entities/recording/types.ts @@ -0,0 +1,23 @@ +export interface VoiceRecording { + id: string; + user_id: string; + username: string; + avatar_url: string | null; + guild_id: string | null; + channel_id: string | null; + channel_name: string | null; + filename: string; + size_bytes: number; + download_url: string | null; + upload_status: "pending" | "uploaded" | "failed"; + upload_error: string | null; + transcription?: string | null; + created_at: number; + uploaded_at: number | null; +} + +export interface VoiceRecordingListResponse { + items: VoiceRecording[]; + nextCursor: string | null; + hasMore: boolean; +} diff --git a/services/frontend/src/entities/ui/types.ts b/services/frontend/src/entities/ui/types.ts new file mode 100644 index 0000000..8427530 --- /dev/null +++ b/services/frontend/src/entities/ui/types.ts @@ -0,0 +1,18 @@ +export interface UIState { + selectedGuild?: string; + selectedVoiceGuild?: string; + selectedVoiceChannel?: string; + selectedTextGuild?: string; + selectedTextChannel?: string; + selectedAnalyticsGuild?: string; + selectedAnalyticsChannel?: string; + activeTab?: "live" | "messages" | "dashboard"; + isListening?: boolean; + isStreaming?: boolean; +} + +export type DashboardTab = "live" | "messages" | "dashboard"; + +export interface AppConfig { + monitorGuildId: string | null; +} diff --git a/services/frontend/src/entities/voice/types.ts b/services/frontend/src/entities/voice/types.ts new file mode 100644 index 0000000..71571df --- /dev/null +++ b/services/frontend/src/entities/voice/types.ts @@ -0,0 +1,17 @@ +import type { GuildVoiceEntry } from "../guild/types"; + +export interface VoiceStatus { + connected: boolean; + activeGuildId: string | null; + activeChannelId: string | null; + activeChannelName: string | null; + connections: GuildVoiceEntry[]; +} + +export interface ActiveSpeaker { + id?: string; + userId?: string; + username: string; + avatar: string; + speaking: boolean; +} diff --git a/services/frontend/src/features/auth/index.tsx b/services/frontend/src/features/auth/index.tsx index a566a31..aa04697 100644 --- a/services/frontend/src/features/auth/index.tsx +++ b/services/frontend/src/features/auth/index.tsx @@ -1,7 +1,7 @@ +import { motion } from "framer-motion"; import { Lock } from "lucide-react"; -import { useEffect, useState } from "react"; -import { login } from "../../shared/api/client"; -import { useGsapTransition } from "../../shared/hooks/useGsapTransition"; +import { useState } from "react"; +import { login } from "../../shared/api/client.js"; import { Button, Card, @@ -20,11 +20,6 @@ export function AuthOverlay({ onAuthenticated }: AuthOverlayProps) { const [password, setPassword] = useState(""); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); - const { pageRef, animateIn } = useGsapTransition("auth"); - - useEffect(() => { - animateIn(); - }, [animateIn]); const handleSubmit = async (e: { preventDefault: () => void }) => { e.preventDefault(); @@ -42,7 +37,12 @@ export function AuthOverlay({ onAuthenticated }: AuthOverlayProps) { }; return ( -
+
@@ -77,6 +77,6 @@ export function AuthOverlay({ onAuthenticated }: AuthOverlayProps) { -
+
); } diff --git a/services/frontend/src/features/dashboard/components/ChannelProfileDetail.tsx b/services/frontend/src/features/dashboard/components/ChannelProfileDetail.tsx index d817103..fb44b92 100644 --- a/services/frontend/src/features/dashboard/components/ChannelProfileDetail.tsx +++ b/services/frontend/src/features/dashboard/components/ChannelProfileDetail.tsx @@ -1,5 +1,5 @@ import { Hash } from "lucide-react"; -import type { DashboardChannelDetail } from "../../../shared/api/client"; +import type { DashboardChannelDetail } from "../../../entities/dashboard/types.js"; import { ProfileDetail } from "../../../shared/ui"; interface ChannelProfileDetailProps { diff --git a/services/frontend/src/features/dashboard/components/ChannelSummaryList.tsx b/services/frontend/src/features/dashboard/components/ChannelSummaryList.tsx index 72998b1..2f82463 100644 --- a/services/frontend/src/features/dashboard/components/ChannelSummaryList.tsx +++ b/services/frontend/src/features/dashboard/components/ChannelSummaryList.tsx @@ -1,5 +1,5 @@ import { Hash } from "lucide-react"; -import type { DashboardChannel } from "../../../shared/api/client"; +import type { DashboardChannel } from "../../../entities/dashboard/types.js"; import type { SummaryItem } from "../../../shared/ui"; import { SummaryList } from "../../../shared/ui"; diff --git a/services/frontend/src/features/dashboard/components/DashboardStats.tsx b/services/frontend/src/features/dashboard/components/DashboardStats.tsx index b5fe7c0..11a5537 100644 --- a/services/frontend/src/features/dashboard/components/DashboardStats.tsx +++ b/services/frontend/src/features/dashboard/components/DashboardStats.tsx @@ -10,7 +10,7 @@ import { Users, } from "lucide-react"; import { cardItem, cardStagger } from "../../../shared/hooks/useFramerStagger"; -import { useUIState } from "../../../shared/hooks/useUIState"; +import { useUIState } from "../../../shared/hooks/useUIState.js"; import { cn } from "../../../shared/lib/utils"; import { Card, @@ -168,7 +168,7 @@ export function DashboardStatsContent() {

) : (
- {stats.top_channels.map((ch, i) => ( + {stats.top_channels.map((ch) => (
- {images.map((image, index) => { + {images.map((image) => { // Stable key using message.id + url const stableKey = `${image.message.id}-${image.kind}-${image.url}`; return ( diff --git a/services/frontend/src/features/messages/components/MessageCard.tsx b/services/frontend/src/features/messages/components/MessageCard.tsx index 919b88d..9f63719 100644 --- a/services/frontend/src/features/messages/components/MessageCard.tsx +++ b/services/frontend/src/features/messages/components/MessageCard.tsx @@ -9,8 +9,8 @@ import { Trash2, } from "lucide-react"; import { Fragment, useMemo, useState } from "react"; -import { parseMetadata } from "../../../entities/message/types"; -import type { MessageRecord } from "../../../shared/api/client"; +import type { MessageRecord } from "../../../entities/message/types.js"; +import { parseMetadata } from "../../../shared/lib/utils.js"; import { Badge, Button, Skeleton, StatusBadge } from "../../../shared/ui"; const CUSTOM_EMOJI_REGEX = /<(a)?:([a-zA-Z0-9_]+):(\d+)>/g; @@ -72,12 +72,6 @@ function parseStringList(value?: string | null): string[] { } } -function aiVariant(status: string) { - if (status === "clean") return "success"; - if (status === "flagged" || status === "error") return "destructive"; - return "secondary"; -} - function severityColor(severity: string) { switch (severity) { case "critical": diff --git a/services/frontend/src/features/messages/components/MessageFeed.tsx b/services/frontend/src/features/messages/components/MessageFeed.tsx index 076e59a..2064fd3 100644 --- a/services/frontend/src/features/messages/components/MessageFeed.tsx +++ b/services/frontend/src/features/messages/components/MessageFeed.tsx @@ -1,6 +1,6 @@ import { motion } from "framer-motion"; import { useEffect, useMemo, useRef } from "react"; -import type { MessageRecord } from "../../../shared/api/client"; +import type { MessageRecord } from "../../../entities/message/types.js"; import { cardItem, cardStagger } from "../../../shared/hooks/useFramerStagger"; import { ScrollArea } from "../../../shared/ui"; import { EmptyStateMascot } from "../../../widgets/mascot/MascotImage"; diff --git a/services/frontend/src/features/messages/hooks/useMessages.ts b/services/frontend/src/features/messages/hooks/useMessages.ts index 82de34c..24b23d4 100644 --- a/services/frontend/src/features/messages/hooks/useMessages.ts +++ b/services/frontend/src/features/messages/hooks/useMessages.ts @@ -1,5 +1,5 @@ import { useCallback, useRef, useState } from "react"; -import type { MessageRecord } from "../../../shared/api/client"; +import type { MessageRecord } from "../../../entities/message/types.js"; import { listMessages, reanalyzeErrorBatch, diff --git a/services/frontend/src/features/messages/index.tsx b/services/frontend/src/features/messages/index.tsx index 1a50719..b52b1fd 100644 --- a/services/frontend/src/features/messages/index.tsx +++ b/services/frontend/src/features/messages/index.tsx @@ -1,7 +1,8 @@ import { motion } from "framer-motion"; import { Filter, RotateCw, Search, X } from "lucide-react"; import { useMemo, useState } from "react"; -import { type MessageRecord, request } from "../../shared/api/client"; +import type { MessageRecord } from "../../shared/api/client"; +import { request } from "../../shared/api/client"; import { cardItem, cardStagger } from "../../shared/hooks/useFramerStagger"; import { Badge, diff --git a/services/frontend/src/main.tsx b/services/frontend/src/main.tsx index fc4ae6a..1b16609 100644 --- a/services/frontend/src/main.tsx +++ b/services/frontend/src/main.tsx @@ -1,21 +1,9 @@ -import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App"; import { ToastProvider } from "./shared/ui"; import "./styles.css"; -const queryClient = new QueryClient({ - defaultOptions: { - queries: { - staleTime: 30_000, // data stays fresh for 30s — no refetch within this window - gcTime: 5 * 60_000, // keep unused data in cache for 5 minutes - refetchOnWindowFocus: false, // avoid spamming the API on tab switches - retry: 2, - }, - }, -}); - const root = document.getElementById("root"); if (!root) { @@ -24,10 +12,8 @@ if (!root) { ReactDOM.createRoot(root).render( - - - - - + + + , ); diff --git a/services/frontend/src/shared/api/client.ts b/services/frontend/src/shared/api/client.ts index ff8f1d1..1d3500d 100644 --- a/services/frontend/src/shared/api/client.ts +++ b/services/frontend/src/shared/api/client.ts @@ -1,6 +1,34 @@ // ─── Shared HTTP client — all API endpoints in one file ────────────────────── import type { MessageRecord, PageResult } from "@bete/shared"; +import type { + ChatResponse, + DashboardChannel, + DashboardChannelDetail, + DashboardStats, + DashboardUser, + DashboardUserDetail, +} from "../../entities/dashboard/types.js"; +import type { + Channel, + Guild, + GuildVoiceEntry, +} from "../../entities/guild/types.js"; +import type { + MediaItem, + MediaMode, + MediaState, +} from "../../entities/media/types.js"; +import type { + VoiceRecording, + VoiceRecordingListResponse, +} from "../../entities/recording/types.js"; +import type { + AppConfig, + DashboardTab, + UIState, +} from "../../entities/ui/types.js"; +import type { ActiveSpeaker, VoiceStatus } from "../../entities/voice/types.js"; import { createLogger } from "../lib/logger.js"; const logger = createLogger("api"); @@ -85,86 +113,31 @@ export function getAPIURL(): string { return BE_API_URL; } -// ─── Types ─────────────────────────────────────────────────────────────────── +// ─── Re-exports ────────────────────────────────────────────────────────────── -export type { MessageRecord, PageResult }; - -export interface Guild { - id: string; - name: string; - icon: string | null; -} - -export interface Channel { - id: string; - name: string; - type?: string; - parentId?: string | null; -} - -export interface GuildVoiceEntry { - guildId: string; - channelId: string; - channelName: string; - connectedAt: number; -} - -export interface VoiceStatus { - connected: boolean; - activeGuildId: string | null; - activeChannelId: string | null; - activeChannelName: string | null; - connections: GuildVoiceEntry[]; -} - -export interface ActiveSpeaker { - id?: string; - userId?: string; - username: string; - avatar: string; - speaking: boolean; -} - -export type MediaMode = "music" | "screen"; - -export interface MediaItem { - id?: string; - source: string; - title: string; - mode?: "music" | "screen"; - durationMs?: number | null; - thumbnailUrl?: string | null; -} - -export interface MediaState { - playing: boolean; - musicVolume: number; - current: MediaItem | null; - queue: MediaItem[]; -} - -export interface UIState { - selectedGuild?: string; - selectedVoiceGuild?: string; - selectedVoiceChannel?: string; - selectedTextGuild?: string; - selectedTextChannel?: string; - selectedAnalyticsGuild?: string; - selectedAnalyticsChannel?: string; - activeTab?: "live" | "messages" | "dashboard"; - isListening?: boolean; - isStreaming?: boolean; -} - -export interface AppConfig { - monitorGuildId: string | null; -} - -export interface ChatResponse { - response?: string; -} - -export type DashboardTab = "live" | "messages" | "dashboard"; +export type { + ActiveSpeaker, + AppConfig, + Channel, + ChatResponse, + DashboardChannel, + DashboardChannelDetail, + DashboardStats, + DashboardTab, + DashboardUser, + DashboardUserDetail, + Guild, + GuildVoiceEntry, + MediaItem, + MediaMode, + MediaState, + MessageRecord, + PageResult, + UIState, + VoiceRecording, + VoiceRecordingListResponse, + VoiceStatus, +}; // ─── Messages ──────────────────────────────────────────────────────────────── @@ -275,30 +248,6 @@ export function setMediaVolume(volume: number): Promise { // ─── Recordings ────────────────────────────────────────────────────────────── -export interface VoiceRecording { - id: string; - user_id: string; - username: string; - avatar_url: string | null; - guild_id: string | null; - channel_id: string | null; - channel_name: string | null; - filename: string; - size_bytes: number; - download_url: string | null; - upload_status: "pending" | "uploaded" | "failed"; - upload_error: string | null; - transcription?: string | null; - created_at: number; - uploaded_at: number | null; -} - -export interface VoiceRecordingListResponse { - items: VoiceRecording[]; - nextCursor: string | null; - hasMore: boolean; -} - export function listRecordings(params?: { limit?: number; cursor?: string; @@ -325,55 +274,6 @@ export function login(password: string): Promise<{ ok: boolean }> { // ─── Dashboard ───────────────────────────────────────────────────────────────── -export interface DashboardStats { - total_messages: number; - total_users: number; - total_flagged: number; - total_clean: number; - total_warned: number; - total_error: number; - total_voice_recordings: number; - total_profiles: number; - today_messages: number; - today_flagged: number; - active_users_24h: number; - top_channels: Array<{ - channel_id: string; - channel_name: string | null; - message_count: number; - }>; - moderation_overview: { - pending: number; - processing: number; - error: number; - }; -} - -export interface DashboardUser { - user_id: string; - username: string | null; - avatar_url: string | null; - profile_summary: string | null; - total_messages: number; - flagged_count: number; - last_message_at: number | null; - trust_score: number | null; -} - -export interface DashboardUserDetail extends DashboardUser { - last_analyzed_at: number | null; - clean_message_streak: number | null; - total_infractions: number | null; - clean_count: number; - recent_messages: Array<{ - id: string; - content: string; - channel_id: string; - created_at: number; - ai_status: string | null; - }>; -} - export function getDashboardStats(): Promise { return request("/api/dashboard/stats"); } @@ -399,29 +299,6 @@ export function getDashboardUserDetail( // ─── Dashboard Channels ───────────────────────────────────────────────────────── -export interface DashboardChannel { - channel_id: string; - channel_name: string | null; - guild_id: string | null; - total_messages: number; - flagged_count: number; - last_message_at: number | null; - culture_summary: string | null; - last_analyzed_at: number | null; -} - -export interface DashboardChannelDetail extends DashboardChannel { - clean_count: number; - recent_messages: Array<{ - id: string; - content: string; - channel_id: string; - created_at: number; - ai_status: string | null; - username: string | null; - }>; -} - export function listDashboardChannels( params: { limit?: number; diff --git a/services/frontend/src/shared/hooks/useAudioTransmit.ts b/services/frontend/src/shared/hooks/useAudioTransmit.ts index 92d238c..2c8f3c9 100644 --- a/services/frontend/src/shared/hooks/useAudioTransmit.ts +++ b/services/frontend/src/shared/hooks/useAudioTransmit.ts @@ -1,6 +1,7 @@ // ─── Audio transmit hook — captures mic, encodes to PCM, sends via WebSocket ── import { useCallback, useRef, useState } from "react"; import { getAPIURL } from "../api/client.js"; +// note: this hook only uses API functions, not entity types import { createLogger } from "../lib/logger"; const SAMPLE_RATE = 24000; diff --git a/services/frontend/src/shared/hooks/useGsapTransition.ts b/services/frontend/src/shared/hooks/useGsapTransition.ts deleted file mode 100644 index 84bdebd..0000000 --- a/services/frontend/src/shared/hooks/useGsapTransition.ts +++ /dev/null @@ -1,123 +0,0 @@ -import gsap from "gsap"; -import { useCallback, useEffect, useRef } from "react"; - -function prefersReducedMotion(): boolean { - if (typeof window === "undefined") return false; - return window.matchMedia("(prefers-reduced-motion: reduce)").matches; -} - -export function useGsapTransition(tabKey: string) { - const pageRef = useRef(null); - const ctxRef = useRef(null); - - const animateIn = useCallback(() => { - // Kill any previously recorded animations to prevent conflicts - ctxRef.current?.kill(); - - const instant = prefersReducedMotion(); - const scope = pageRef.current ?? undefined; - - const ctx = gsap.context(() => { - const tl = gsap.timeline(); - - // Page container: fade-in + slide-up (400ms ease-out) - if (pageRef.current) { - tl.fromTo( - pageRef.current, - { opacity: 0, y: 20 }, - { - opacity: 1, - y: 0, - duration: instant ? 0 : 0.4, - ease: "power2.out", - }, - ); - } - - // Stagger children with data-stagger attribute - const staggerEls = - pageRef.current?.querySelectorAll("[data-stagger]"); - if (staggerEls && staggerEls.length > 0) { - tl.fromTo( - staggerEls, - { opacity: 0, y: 15 }, - { - opacity: 1, - y: 0, - duration: instant ? 0 : 0.3, - stagger: instant ? 0 : 0.05, - ease: "power2.out", - }, - "-=0.1", - ); - } - }, scope); - - ctxRef.current = ctx; - }, [tabKey]); - - const animateOut = useCallback((): Promise => { - // Kill any previously recorded animations to prevent conflicts - ctxRef.current?.kill(); - - return new Promise((resolve) => { - const instant = prefersReducedMotion(); - const scope = pageRef.current ?? undefined; - - const ctx = gsap.context(() => { - const tl = gsap.timeline({ - onComplete: () => { - resolve(); - }, - }); - - if (pageRef.current) { - // Page container: fade-out + slide-down (300ms ease-in) - tl.to(pageRef.current, { - opacity: 0, - y: 20, - duration: instant ? 0 : 0.3, - ease: "power2.in", - }); - } else { - // No element to animate — resolve immediately - resolve(); - } - }, scope); - - ctxRef.current = ctx; - }); - }, [tabKey]); - - // Cleanup all recorded animations on unmount - useEffect(() => { - return () => { - ctxRef.current?.kill(); - }; - }, []); - - return { pageRef, animateIn, animateOut }; -} - -function gsapCardHover() { - return { - onMouseEnter: (e: React.MouseEvent) => { - gsap.to(e.currentTarget, { - y: -4, - boxShadow: "0 8px 25px rgba(0,0,0,0.15)", - duration: 0.2, - ease: "power2.out", - overwrite: "auto", - }); - }, - onMouseLeave: (e: React.MouseEvent) => { - gsap.to(e.currentTarget, { - y: 0, - boxShadow: "0 2px 8px rgba(0,0,0,0.08)", - duration: 0.2, - ease: "power2.out", - overwrite: "auto", - }); - }, - }; -} diff --git a/services/frontend/src/shared/hooks/useMascotChat.ts b/services/frontend/src/shared/hooks/useMascotChat.ts index a4f2031..43eaf6f 100644 --- a/services/frontend/src/shared/hooks/useMascotChat.ts +++ b/services/frontend/src/shared/hooks/useMascotChat.ts @@ -1,5 +1,5 @@ import { useCallback, useState } from "react"; -import type { ChatResponse } from "../api/client"; +import type { ChatResponse } from "../../entities/dashboard/types.js"; import { request } from "../api/client"; import { createLogger } from "../lib/logger"; diff --git a/services/frontend/src/shared/hooks/useMascotSummary.ts b/services/frontend/src/shared/hooks/useMascotSummary.ts deleted file mode 100644 index 96ec339..0000000 --- a/services/frontend/src/shared/hooks/useMascotSummary.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { useEffect, useState } from "react"; -import type { MessageRecord } from "../api/client"; - -/** - * useMascotSummary — Generates AI-powered summary/insights from recent messages - * Used by mascot's floating chat bubble to display conversation insights - */ - -interface UseMascotSummaryOptions { - messages: MessageRecord[]; - enabled?: boolean; -} - -const summaryPrompts = [ - "📊 Diskusi sangat aktif dengan {count} pesan", - "💬 Topik populer: {topic} ({percentage}%)", - "👥 Partisipan utama: {users}", - "⏰ Aktivitas puncak: {time}", - "🔥 Buzz level: {level}", - "💡 Insight: {insight}", -]; - -function generateInsight(messages: MessageRecord[]): string { - if (messages.length === 0) { - return "Menunggu pesan..."; - } - - const totalMessages = messages.length; - const recentMessages = messages.slice(-10); - - // Hitung user yang berbeda - const uniqueUsers = new Set(recentMessages.map((m) => m.user_id)).size; - - // Hitung average panjang pesan - const avgLength = Math.round( - recentMessages.reduce((sum, m) => sum + (m.content?.length || 0), 0) / - recentMessages.length, - ); - - // Tentukan tipe percakapan - let insight = ""; - if (avgLength > 150) { - insight = "Diskusi mendalam sedang berlangsung"; - } else if (avgLength > 80) { - insight = "Percakapan normal dan interaktif"; - } else { - insight = "Chat cepat dan ringkas"; - } - - // Tambah info partisipan - if (uniqueUsers > 5) { - insight += ` • ${uniqueUsers} orang aktif`; - } - - // Tambah info volume - if (totalMessages > 50) { - insight += " • Volume tinggi 🔥"; - } else if (totalMessages > 20) { - insight += " • Percakapan aktif"; - } - - return insight; -} - -function extractTopics(messages: MessageRecord[]): string { - if (messages.length === 0) return "Tidak ada topik"; - - // Extract keywords dari recent messages - const recentMessages = messages.slice(-15); - const content = recentMessages - .map((m) => m.content?.toLowerCase() || "") - .join(" "); - - // Simple keyword extraction - const keywords = [ - { word: "voice", label: "Voice" }, - { word: "recording", label: "Recording" }, - { word: "audio", label: "Audio" }, - { word: "chat", label: "Chat" }, - { word: "message", label: "Message" }, - { word: "user", label: "User" }, - ]; - - for (const { word, label } of keywords) { - if (content.includes(word)) { - return label; - } - } - - return "Umum"; -} - -export function useMascotSummary({ - messages, - enabled = true, -}: UseMascotSummaryOptions): string { - const [summary, setSummary] = useState(""); - - useEffect(() => { - if (!enabled || messages.length === 0) { - setSummary(""); - return; - } - - // Generate summary berdasarkan messages - const insight = generateInsight(messages); - setSummary(insight); - - // Rotate summary setiap 5 detik - const interval = setInterval(() => { - setSummary((prev) => { - if (prev.includes("aktif")) { - return `📈 Total: ${messages.length} pesan`; - } else if (prev.includes("Total")) { - return generateInsight(messages); - } - return prev; - }); - }, 5000); - - return () => clearInterval(interval); - }, [messages, enabled]); - - return summary; -} diff --git a/services/frontend/src/shared/hooks/useUIState.ts b/services/frontend/src/shared/hooks/useUIState.ts index b3c69fa..2ad1acc 100644 --- a/services/frontend/src/shared/hooks/useUIState.ts +++ b/services/frontend/src/shared/hooks/useUIState.ts @@ -1,5 +1,5 @@ import { useCallback } from "react"; -import type { UIState } from "../api/client"; +import type { UIState } from "../../entities/ui/types.js"; import { uiStateValidator, useLocalStorage } from "./useLocalStorage"; export function useUIState() { diff --git a/services/frontend/src/shared/lib/utils.ts b/services/frontend/src/shared/lib/utils.ts index 052d3ce..ab20ca6 100644 --- a/services/frontend/src/shared/lib/utils.ts +++ b/services/frontend/src/shared/lib/utils.ts @@ -16,3 +16,25 @@ export function formatBytes(bytes: number): string { export function formatDate(value: number): string { return new Date(value).toLocaleString(); } + +export interface MessageMetadata { + stickers?: Array<{ name?: string; url?: string }>; + attachments?: Array<{ name: string; url: string; contentType?: string }>; + embeds?: Array<{ title?: string; image?: string; thumbnail?: string }>; + channel?: { + channelId: string; + channelName?: string; + threadId?: string; + threadName?: string; + }; +} + +export function parseMetadata(value: string | null): MessageMetadata { + if (!value) return {}; + try { + const parsed = JSON.parse(value) as MessageMetadata; + return parsed; + } catch { + return {}; + } +} diff --git a/services/frontend/src/shared/ui/MobileTabBar.tsx b/services/frontend/src/shared/ui/MobileTabBar.tsx index 6be0f90..a26d87d 100644 --- a/services/frontend/src/shared/ui/MobileTabBar.tsx +++ b/services/frontend/src/shared/ui/MobileTabBar.tsx @@ -1,5 +1,5 @@ import { LayoutDashboard, MessageSquare, Radio } from "lucide-react"; -import type { DashboardTab } from "../api/client"; +import type { DashboardTab } from "../../entities/ui/types.js"; import { cn } from "../lib/utils"; const tabs: Array<{ id: DashboardTab; label: string; Icon: typeof Radio }> = [ diff --git a/services/frontend/src/shared/ui/toast.tsx b/services/frontend/src/shared/ui/toast.tsx index 2064e16..267bc9e 100644 --- a/services/frontend/src/shared/ui/toast.tsx +++ b/services/frontend/src/shared/ui/toast.tsx @@ -1,4 +1,5 @@ // ─── Toast notification system ────────────────────────────────────────────── +// (no entity type imports needed — only uses string/ReactNode) import { AlertCircle, AlertTriangle, diff --git a/services/frontend/src/shared/ws/socket.ts b/services/frontend/src/shared/ws/socket.ts index 855d6f0..86b616e 100644 --- a/services/frontend/src/shared/ws/socket.ts +++ b/services/frontend/src/shared/ws/socket.ts @@ -1,6 +1,14 @@ // ─── WebSocket singleton with reconnect, typed events, and observable status ─ + +import type { + AttachmentRecord, + MessageRecord, + VoiceRecordingUploadData, +} from "@bete/shared"; import { useCallback, useEffect, useRef, useState } from "react"; +import type { MediaState } from "../../entities/media/types.js"; import { createLogger } from "../lib/logger.js"; +import type { ActiveSpeakerData } from "./events.js"; const logger = createLogger("socket"); @@ -23,30 +31,48 @@ function computeBackoff(attempt: number): number { export interface WsHandlers { onBinary?: BinaryHandler; - onMessageCreated?: (data: unknown) => void; - onMessageUpdated?: (data: unknown) => void; - onMessageDeleted?: (data: unknown) => void; - onMessageAnalyzed?: (data: unknown) => void; - onAttachmentCreated?: (data: unknown) => void; - onAttachmentUploaded?: (data: unknown) => void; - onUserState?: (users: unknown[]) => void; - onUiState?: (state: unknown) => void; - onMediaState?: (state: unknown) => void; - onVoiceRecordingStarted?: (data: unknown) => void; - onVoiceRecordingStopped?: (data: unknown) => void; - onVoiceRecordingUploaded?: (data: unknown) => void; - onVoicePcmData?: (data: unknown) => void; - onVoiceActiveUser?: (data: unknown) => void; - onReactionAdded?: (data: unknown) => void; - onReactionRemoved?: (data: unknown) => void; - onThreadCreated?: (data: unknown) => void; - onThreadDeleted?: (data: unknown) => void; - onThreadUpdated?: (data: unknown) => void; - onChannelTopicUpdated?: (data: unknown) => void; - onPresenceUpdated?: (data: unknown) => void; - onGuildMemberAdded?: (data: unknown) => void; - onGuildMemberRemoved?: (data: unknown) => void; - onVoiceAnalyzed?: (data: unknown) => void; + onMessageCreated?: (data: MessageRecord) => void; + onMessageUpdated?: ( + data: MessageRecord & { edited_content?: string | null }, + ) => void; + onMessageDeleted?: (data: { + id: string; + channel_id?: string; + deleted_at: number; + }) => void; + onMessageAnalyzed?: (data: MessageRecord) => void; + onAttachmentCreated?: (data: AttachmentRecord) => void; + onAttachmentUploaded?: (data: AttachmentRecord) => void; + onUserState?: (users: ActiveSpeakerData[]) => void; + onUiState?: (state: Record) => void; + onMediaState?: (state: MediaState) => void; + onVoiceRecordingStarted?: (data: Record) => void; + onVoiceRecordingStopped?: (data: { + guild_id: string; + session_id: string; + duration_ms: number; + participants: number; + segment_count: number; + status: string; + stopped_at: number; + }) => void; + onVoiceRecordingUploaded?: (data: VoiceRecordingUploadData) => void; + onVoicePcmData?: (data: { + userId: string; + pcm: string; + metadata?: Record; + }) => void; + onVoiceActiveUser?: (data: ActiveSpeakerData) => void; + onReactionAdded?: (data: Record) => void; + onReactionRemoved?: (data: Record) => void; + onThreadCreated?: (data: Record) => void; + onThreadDeleted?: (data: Record) => void; + onThreadUpdated?: (data: Record) => void; + onChannelTopicUpdated?: (data: Record) => void; + onPresenceUpdated?: (data: Record) => void; + onGuildMemberAdded?: (data: Record) => void; + onGuildMemberRemoved?: (data: Record) => void; + onVoiceAnalyzed?: (data: Record) => void; } let _wsInstance: WebSocket | null = null; @@ -110,76 +136,125 @@ function doConnect(): WebSocket { for (const h of _listeners) { switch (msg.type) { case "message_created": - if (msg.data !== undefined) h.onMessageCreated?.(msg.data); + if (msg.data !== undefined) + h.onMessageCreated?.(msg.data as MessageRecord); break; case "message_updated": - if (msg.data !== undefined) h.onMessageUpdated?.(msg.data); + if (msg.data !== undefined) + h.onMessageUpdated?.( + msg.data as MessageRecord & { edited_content?: string | null }, + ); break; case "message_deleted": - if (msg.data !== undefined) h.onMessageDeleted?.(msg.data); + if (msg.data !== undefined) + h.onMessageDeleted?.( + msg.data as { + id: string; + channel_id?: string; + deleted_at: number; + }, + ); break; case "message_analyzed": - if (msg.data !== undefined) h.onMessageAnalyzed?.(msg.data); + if (msg.data !== undefined) + h.onMessageAnalyzed?.(msg.data as MessageRecord); break; case "attachment_created": - if (msg.data !== undefined) h.onAttachmentCreated?.(msg.data); + if (msg.data !== undefined) + h.onAttachmentCreated?.(msg.data as AttachmentRecord); break; case "attachment_uploaded": - if (msg.data !== undefined) h.onAttachmentUploaded?.(msg.data); + if (msg.data !== undefined) + h.onAttachmentUploaded?.(msg.data as AttachmentRecord); break; case "user_state": - h.onUserState?.((msg.users as unknown[]) || []); + h.onUserState?.( + (msg.users as unknown as ActiveSpeakerData[]) || [], + ); break; case "ui_state": - h.onUiState?.(msg.state); + h.onUiState?.(msg.state as Record); break; case "media_state": - h.onMediaState?.(msg.state); + h.onMediaState?.(msg.state as MediaState); break; case "voice_recording_started": - if (msg.data !== undefined) h.onVoiceRecordingStarted?.(msg.data); + if (msg.data !== undefined) + h.onVoiceRecordingStarted?.(msg.data as Record); break; case "voice_recording_stopped": - if (msg.data !== undefined) h.onVoiceRecordingStopped?.(msg.data); + if (msg.data !== undefined) + h.onVoiceRecordingStopped?.( + msg.data as { + guild_id: string; + session_id: string; + duration_ms: number; + participants: number; + segment_count: number; + status: string; + stopped_at: number; + }, + ); break; case "voice_recording_uploaded": - if (msg.data !== undefined) h.onVoiceRecordingUploaded?.(msg.data); + if (msg.data !== undefined) + h.onVoiceRecordingUploaded?.( + msg.data as VoiceRecordingUploadData, + ); break; case "voice_pcm_data": - if (msg.data !== undefined) h.onVoicePcmData?.(msg.data); + if (msg.data !== undefined) + h.onVoicePcmData?.( + msg.data as { + userId: string; + pcm: string; + metadata?: Record; + }, + ); break; case "voice_active_user": - if (msg.data !== undefined) h.onVoiceActiveUser?.(msg.data); + if (msg.data !== undefined) + h.onVoiceActiveUser?.(msg.data as ActiveSpeakerData); break; case "voice_analyzed": - if (msg.data !== undefined) h.onVoiceAnalyzed?.(msg.data); + if (msg.data !== undefined) + h.onVoiceAnalyzed?.(msg.data as Record); break; case "reaction_added": - if (msg.data !== undefined) h.onReactionAdded?.(msg.data); + if (msg.data !== undefined) + h.onReactionAdded?.(msg.data as Record); break; case "reaction_removed": - if (msg.data !== undefined) h.onReactionRemoved?.(msg.data); + if (msg.data !== undefined) + h.onReactionRemoved?.(msg.data as Record); break; case "thread_created": - if (msg.data !== undefined) h.onThreadCreated?.(msg.data); + if (msg.data !== undefined) + h.onThreadCreated?.(msg.data as Record); break; case "thread_deleted": - if (msg.data !== undefined) h.onThreadDeleted?.(msg.data); + if (msg.data !== undefined) + h.onThreadDeleted?.(msg.data as Record); break; case "thread_updated": - if (msg.data !== undefined) h.onThreadUpdated?.(msg.data); + if (msg.data !== undefined) + h.onThreadUpdated?.(msg.data as Record); break; case "channel_topic_updated": - if (msg.data !== undefined) h.onChannelTopicUpdated?.(msg.data); + if (msg.data !== undefined) + h.onChannelTopicUpdated?.(msg.data as Record); break; case "presence_updated": - if (msg.data !== undefined) h.onPresenceUpdated?.(msg.data); + if (msg.data !== undefined) + h.onPresenceUpdated?.(msg.data as Record); break; case "guild_member_added": - if (msg.data !== undefined) h.onGuildMemberAdded?.(msg.data); + if (msg.data !== undefined) + h.onGuildMemberAdded?.(msg.data as Record); break; case "guild_member_removed": - if (msg.data !== undefined) h.onGuildMemberRemoved?.(msg.data); + if (msg.data !== undefined) + h.onGuildMemberRemoved?.(msg.data as Record); break; case "analysis_queue_status": // monitoring-only — no UI action needed diff --git a/services/frontend/src/widgets/DashboardLayout.tsx b/services/frontend/src/widgets/DashboardLayout.tsx index 8741ab3..12ae55c 100644 --- a/services/frontend/src/widgets/DashboardLayout.tsx +++ b/services/frontend/src/widgets/DashboardLayout.tsx @@ -1,10 +1,8 @@ import { motion } from "framer-motion"; import type { ReactNode } from "react"; -import type { - DashboardTab, - MessageRecord, - VoiceStatus, -} from "../shared/api/client"; +import type { MessageRecord } from "../entities/message/types.js"; +import type { DashboardTab } from "../entities/ui/types.js"; +import type { VoiceStatus } from "../entities/voice/types.js"; import { fadeSlideUp } from "../shared/hooks/useFramerStagger"; import type { WsStatus } from "../shared/ws/socket"; import { Header } from "./Header"; diff --git a/services/frontend/src/widgets/Header.tsx b/services/frontend/src/widgets/Header.tsx index 428e664..f6d4d73 100644 --- a/services/frontend/src/widgets/Header.tsx +++ b/services/frontend/src/widgets/Header.tsx @@ -1,6 +1,7 @@ import { motion } from "framer-motion"; import { Wifi, WifiOff } from "lucide-react"; -import type { DashboardTab, VoiceStatus } from "../shared/api/client"; +import type { DashboardTab } from "../entities/ui/types.js"; +import type { VoiceStatus } from "../entities/voice/types.js"; import { fadeSlideUp } from "../shared/hooks/useFramerStagger"; import { cn } from "../shared/lib/utils"; import { Badge } from "../shared/ui"; diff --git a/services/frontend/src/widgets/Sidebar.tsx b/services/frontend/src/widgets/Sidebar.tsx index b2f2342..9c8bb10 100644 --- a/services/frontend/src/widgets/Sidebar.tsx +++ b/services/frontend/src/widgets/Sidebar.tsx @@ -1,6 +1,7 @@ import { motion } from "framer-motion"; import { LayoutDashboard, MessageSquare, Radio } from "lucide-react"; -import type { DashboardTab, MessageRecord } from "../shared/api/client"; +import type { MessageRecord } from "../entities/message/types.js"; +import type { DashboardTab } from "../entities/ui/types.js"; import { useMascotChat } from "../shared/hooks/useMascotChat"; import { cn } from "../shared/lib/utils"; import { MascotChatbot } from "./mascot/MascotChatbot"; diff --git a/services/frontend/src/widgets/mascot/MascotChatbot.tsx b/services/frontend/src/widgets/mascot/MascotChatbot.tsx index e19891d..26c22ca 100644 --- a/services/frontend/src/widgets/mascot/MascotChatbot.tsx +++ b/services/frontend/src/widgets/mascot/MascotChatbot.tsx @@ -1,8 +1,11 @@ import { AnimatePresence, motion } from "framer-motion"; import { Maximize2, MessageCircle, Minimize2, Send, X } from "lucide-react"; import { useEffect, useRef, useState } from "react"; +import { createLogger } from "../../shared/lib/logger.js"; import { cn } from "../../shared/lib/utils"; +const logger = createLogger("mascot-chat"); + export interface ChatMessage { id: string; role: "user" | "mascot"; @@ -84,7 +87,9 @@ export function MascotChatbot({ setMessages((prev) => [...prev, mascotMessage]); } catch (error) { - console.error("Error sending message:", error); + logger.error("Error sending message", { + error: error instanceof Error ? error.message : String(error), + }); const errorMessage: ChatMessage = { id: `mascot-error-${Date.now()}`, role: "mascot",